molstar
Version:
A comprehensive macromolecular library.
258 lines (257 loc) • 13.3 kB
JavaScript
/**
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { __assign, __awaiter, __extends, __generator } from "tslib";
import { PluginStateObject, PluginStateTransform } from '../../mol-plugin-state/objects';
import { createSphericalCollocationGrid } from './orbitals';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Task } from '../../mol-task';
import { CustomProperties } from '../../mol-model/custom-property';
import { ColorNames } from '../../mol-util/color/names';
import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers/volume-representation-params';
import { StateTransformer } from '../../mol-state';
import { Theme } from '../../mol-theme/theme';
import { VolumeRepresentation3DHelpers } from '../../mol-plugin-state/transforms/representation';
import { CubeGridFormat, isCubeGridData } from './data-model';
import { createSphericalCollocationDensityGrid } from './density';
var BasisAndOrbitals = /** @class */ (function (_super) {
__extends(BasisAndOrbitals, _super);
function BasisAndOrbitals() {
return _super !== null && _super.apply(this, arguments) || this;
}
return BasisAndOrbitals;
}(PluginStateObject.Create({ name: 'Basis', typeClass: 'Object' })));
export { BasisAndOrbitals };
export var StaticBasisAndOrbitals = PluginStateTransform.BuiltIn({
name: 'static-basis-and-orbitals',
display: 'Basis and Orbitals',
from: PluginStateObject.Root,
to: BasisAndOrbitals,
params: {
label: PD.Text('Orbital Data', { isHidden: true }),
basis: PD.Value(void 0, { isHidden: true }),
order: PD.Text('gaussian', { isHidden: true }),
orbitals: PD.Value([], { isHidden: true })
},
})({
apply: function (_a) {
var params = _a.params;
return new BasisAndOrbitals({ basis: params.basis, order: params.order, orbitals: params.orbitals }, { label: params.label });
}
});
var CreateOrbitalVolumeParamBase = {
cutoffThreshold: PD.Numeric(0.0015, { min: 0, max: 0.1, step: 0.0001 }),
boxExpand: PD.Numeric(4.5, { min: 0, max: 7, step: 0.1 }),
gridSpacing: PD.ObjectList({ atomCount: PD.Numeric(0), spacing: PD.Numeric(0.35, { min: 0.1, max: 2, step: 0.01 }) }, function (e) { return "Atoms ".concat(e.atomCount, ": ").concat(e.spacing); }, {
defaultValue: [
{ atomCount: 55, spacing: 0.5 },
{ atomCount: 40, spacing: 0.45 },
{ atomCount: 25, spacing: 0.4 },
{ atomCount: 0, spacing: 0.35 },
]
}),
clampValues: PD.MappedStatic('off', {
off: PD.EmptyGroup(),
on: PD.Group({
sigma: PD.Numeric(8, { min: 1, max: 20 }, { description: 'Clamp values to range [sigma * negIsoValue, sigma * posIsoValue].' })
})
})
};
function clampData(matrix, min, max) {
for (var i = 0, _i = matrix.length; i < _i; i++) {
var v = matrix[i];
if (v < min)
matrix[i] = min;
else if (v > max)
matrix[i] = max;
}
}
function clampGrid(data, v) {
var _a, _b, _c, _d;
var grid = data.grid;
var min = ((_b = (_a = data.isovalues) === null || _a === void 0 ? void 0 : _a.negative) !== null && _b !== void 0 ? _b : data.grid.stats.min) * v;
var max = ((_d = (_c = data.isovalues) === null || _c === void 0 ? void 0 : _c.positive) !== null && _d !== void 0 ? _d : data.grid.stats.max) * v;
// clamp values for better direct volume resolution
// current implementation uses Byte array for values
// if this is not enough, update mol* to use float
// textures instead
if (grid.stats.min < min || grid.stats.max > max) {
clampData(data.grid.cells.data, min, max);
if (grid.stats.min < min) {
grid.stats.min = min;
}
if (grid.stats.max > max) {
grid.stats.max = max;
}
}
}
export var CreateOrbitalVolume = PluginStateTransform.BuiltIn({
name: 'create-orbital-volume',
display: 'Orbital Volume',
from: BasisAndOrbitals,
to: PluginStateObject.Volume.Data,
params: function (a) {
if (!a) {
return __assign({ index: PD.Numeric(0) }, CreateOrbitalVolumeParamBase);
}
return __assign({ index: PD.Select(0, a.data.orbitals.map(function (o, i) { return [i, "[".concat(i + 1, "] ").concat(o.energy.toFixed(4))]; })) }, CreateOrbitalVolumeParamBase);
}
})({
apply: function (_a, plugin) {
var _this = this;
var a = _a.a, params = _a.params;
return Task.create('Orbital Volume', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
var data, volume;
var _a, _b, _c, _d, _e;
return __generator(this, function (_f) {
switch (_f.label) {
case 0: return [4 /*yield*/, createSphericalCollocationGrid({
basis: a.data.basis,
cutoffThreshold: params.cutoffThreshold,
sphericalOrder: a.data.order,
boxExpand: params.boxExpand,
gridSpacing: params.gridSpacing.map(function (e) { return [e.atomCount, e.spacing]; })
}, a.data.orbitals[params.index], (_a = plugin.canvas3d) === null || _a === void 0 ? void 0 : _a.webgl).runInContext(ctx)];
case 1:
data = _f.sent();
volume = {
grid: data.grid,
sourceData: CubeGridFormat(data),
customProperties: new CustomProperties(),
_propertyData: Object.create(null),
};
if (((_b = params.clampValues) === null || _b === void 0 ? void 0 : _b.name) === 'on') {
clampGrid(data, (_e = (_d = (_c = params.clampValues) === null || _c === void 0 ? void 0 : _c.params) === null || _d === void 0 ? void 0 : _d.sigma) !== null && _e !== void 0 ? _e : 8);
}
return [2 /*return*/, new PluginStateObject.Volume.Data(volume, { label: 'Orbital Volume' })];
}
});
}); });
}
});
export var CreateOrbitalDensityVolume = PluginStateTransform.BuiltIn({
name: 'create-orbital-density-volume',
display: 'Orbital Density Volume',
from: BasisAndOrbitals,
to: PluginStateObject.Volume.Data,
params: CreateOrbitalVolumeParamBase
})({
apply: function (_a, plugin) {
var _this = this;
var a = _a.a, params = _a.params;
return Task.create('Orbital Volume', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
var data, volume;
var _a, _b, _c, _d, _e;
return __generator(this, function (_f) {
switch (_f.label) {
case 0: return [4 /*yield*/, createSphericalCollocationDensityGrid({
basis: a.data.basis,
cutoffThreshold: params.cutoffThreshold,
sphericalOrder: a.data.order,
boxExpand: params.boxExpand,
gridSpacing: params.gridSpacing.map(function (e) { return [e.atomCount, e.spacing]; })
}, a.data.orbitals, (_a = plugin.canvas3d) === null || _a === void 0 ? void 0 : _a.webgl).runInContext(ctx)];
case 1:
data = _f.sent();
volume = {
grid: data.grid,
sourceData: CubeGridFormat(data),
customProperties: new CustomProperties(),
_propertyData: Object.create(null),
};
if (((_b = params.clampValues) === null || _b === void 0 ? void 0 : _b.name) === 'on') {
clampGrid(data, (_e = (_d = (_c = params.clampValues) === null || _c === void 0 ? void 0 : _c.params) === null || _d === void 0 ? void 0 : _d.sigma) !== null && _e !== void 0 ? _e : 8);
}
return [2 /*return*/, new PluginStateObject.Volume.Data(volume, { label: 'Orbital Volume' })];
}
});
}); });
}
});
export var CreateOrbitalRepresentation3D = PluginStateTransform.BuiltIn({
name: 'create-orbital-representation-3d',
display: 'Orbital Representation 3D',
from: PluginStateObject.Volume.Data,
to: PluginStateObject.Volume.Representation3D,
params: {
relativeIsovalue: PD.Numeric(1, { min: 0.01, max: 5, step: 0.01 }),
kind: PD.Select('positive', [['positive', 'Positive'], ['negative', 'Negative']]),
color: PD.Color(ColorNames.blue),
alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }),
xrayShaded: PD.Boolean(false),
pickable: PD.Boolean(true),
tryUseGpu: PD.Boolean(true)
}
})({
canAutoUpdate: function () {
return true;
},
apply: function (_a, plugin) {
var _this = this;
var a = _a.a, srcParams = _a.params;
return Task.create('Orbitals Representation 3D', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
var params, propertyCtx, provider, props, repr;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
params = volumeParams(plugin, a, srcParams);
propertyCtx = { runtime: ctx, assetManager: plugin.managers.asset };
provider = plugin.representation.volume.registry.get(params.type.name);
if (!provider.ensureCustomProperties) return [3 /*break*/, 2];
return [4 /*yield*/, provider.ensureCustomProperties.attach(propertyCtx, a.data)];
case 1:
_b.sent();
_b.label = 2;
case 2:
props = params.type.params || {};
repr = provider.factory(__assign({ webgl: (_a = plugin.canvas3d) === null || _a === void 0 ? void 0 : _a.webgl }, plugin.representation.volume.themes), provider.getParams);
repr.setTheme(Theme.create(plugin.representation.volume.themes, { volume: a.data }, params));
return [4 /*yield*/, repr.createOrUpdate(props, a.data).runInContext(ctx)];
case 3:
_b.sent();
repr.setState({ pickable: srcParams.pickable });
return [2 /*return*/, new PluginStateObject.Volume.Representation3D({ repr: repr, sourceData: a.data }, { label: provider.label, description: VolumeRepresentation3DHelpers.getDescription(props) })];
}
});
}); });
},
update: function (_a, plugin) {
var _this = this;
var a = _a.a, b = _a.b, srcParams = _a.newParams;
return Task.create('Orbitals Representation 3D', function (ctx) { return __awaiter(_this, void 0, void 0, function () {
var newParams, props;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
newParams = volumeParams(plugin, a, srcParams);
props = __assign(__assign({}, b.data.repr.props), newParams.type.params);
b.data.repr.setTheme(Theme.create(plugin.representation.volume.themes, { volume: a.data }, newParams));
return [4 /*yield*/, b.data.repr.createOrUpdate(props, a.data).runInContext(ctx)];
case 1:
_a.sent();
b.data.sourceData = a.data;
b.data.repr.setState({ pickable: srcParams.pickable });
b.description = VolumeRepresentation3DHelpers.getDescription(props);
return [2 /*return*/, StateTransformer.UpdateResult.Updated];
}
});
}); });
}
});
function volumeParams(plugin, volume, params) {
if (!isCubeGridData(volume.data.sourceData))
throw new Error('Invalid data source kind.');
var isovalues = volume.data.sourceData.data.isovalues;
if (!isovalues)
throw new Error('Isovalues are not computed.');
var value = isovalues[params.kind];
return createVolumeRepresentationParams(plugin, volume.data, {
type: 'isosurface',
typeParams: { isoValue: { kind: 'absolute', absoluteValue: (value !== null && value !== void 0 ? value : 1000) * params.relativeIsovalue }, alpha: params.alpha, xrayShaded: params.xrayShaded, tryUseGpu: params.tryUseGpu },
color: 'uniform',
colorParams: { value: params.color }
});
}