123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- /**
- * Copyright (c) 2019-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- * @author Ludovic Autin <ludovic.autin@gmail.com>
- */
- import { PluginStateObject as PSO, PluginStateTransform } from '../../mol-plugin-state/objects';
- import { ParamDefinition as PD } from '../../mol-util/param-definition';
- import { Task } from '../../mol-task';
- import { CellPack as _CellPack, Cell, CellPacking } from './data';
- import { createStructureFromCellPack } from './model';
- import { IngredientFiles } from './util';
- import { Asset } from '../../mol-util/assets';
- import { PluginContext } from '../../mol-plugin/context';
- import { CellPackInfoProvider } from './property';
- import { Structure, StructureSymmetry, Unit, Model } from '../../mol-model/structure';
- import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
- import { Vec3, Quat } from '../../mol-math/linear-algebra';
- import { StateTransformer } from '../../mol-state';
- import { MBRepresentation, MBParams } from './representation';
- import { IsNativeEndianLittle, flipByteOrder } from '../../mol-io/common/binary';
- import { getFloatValue } from './util';
- export const DefaultCellPackBaseUrl = 'https://raw.githubusercontent.com/mesoscope/cellPACK_data/master/cellPACK_database_1.1.0';
- export class CellPack extends PSO.Create<_CellPack>({ name: 'CellPack', typeClass: 'Object' }) { }
- export { ParseCellPack };
- type ParseCellPack = typeof ParseCellPack
- const ParseCellPack = PluginStateTransform.BuiltIn({
- name: 'parse-cellpack',
- display: { name: 'Parse CellPack', description: 'Parse CellPack from JSON data' },
- from: PSO.Format.Json,
- to: CellPack,
- params: a => {
- return {
- resultsFile: PD.File({ accept: '.bin' }),
- baseUrl: PD.Text(DefaultCellPackBaseUrl)
- };
- }
- })({
- apply({ a, params, cache }, plugin: PluginContext) {
- return Task.create('Parse CellPack', async ctx => {
- const cell = a.data as Cell;
- let counter_id = 0;
- let fiber_counter_id = 0;
- let comp_counter = 0;
- const packings: CellPacking[] = [];
- const { compartments, cytoplasme } = cell;
- if (!cell.mapping_ids) cell.mapping_ids = {};
- if (cytoplasme) {
- packings.push({ name: 'Cytoplasme', location: 'cytoplasme', ingredients: cytoplasme.ingredients });
- for (const iName in cytoplasme.ingredients) {
- if (cytoplasme.ingredients[iName].ingtype === 'fiber') {
- cell.mapping_ids[-(fiber_counter_id + 1)] = [comp_counter, iName];
- if (!cytoplasme.ingredients[iName].nbCurve) cytoplasme.ingredients[iName].nbCurve = 0;
- fiber_counter_id++;
- } else {
- cell.mapping_ids[counter_id] = [comp_counter, iName];
- if (!cytoplasme.ingredients[iName].results) { cytoplasme.ingredients[iName].results = []; }
- counter_id++;
- }
- }
- comp_counter++;
- }
- if (compartments) {
- for (const name in compartments) {
- const { surface, interior } = compartments[name];
- let filename = '';
- if (compartments[name].geom_type === 'file') {
- filename = (compartments[name].geom) ? compartments[name].geom as string : '';
- }
- const compartment = { filename: filename, geom_type: compartments[name].geom_type, compartment_primitives: compartments[name].mb };
- if (surface) {
- packings.push({ name, location: 'surface', ingredients: surface.ingredients, compartment: compartment });
- for (const iName in surface.ingredients) {
- if (surface.ingredients[iName].ingtype === 'fiber') {
- cell.mapping_ids[-(fiber_counter_id + 1)] = [comp_counter, iName];
- if (!surface.ingredients[iName].nbCurve) surface.ingredients[iName].nbCurve = 0;
- fiber_counter_id++;
- } else {
- cell.mapping_ids[counter_id] = [comp_counter, iName];
- if (!surface.ingredients[iName].results) { surface.ingredients[iName].results = []; }
- counter_id++;
- }
- }
- comp_counter++;
- }
- if (interior) {
- if (!surface) packings.push({ name, location: 'interior', ingredients: interior.ingredients, compartment: compartment });
- else packings.push({ name, location: 'interior', ingredients: interior.ingredients });
- for (const iName in interior.ingredients) {
- if (interior.ingredients[iName].ingtype === 'fiber') {
- cell.mapping_ids[-(fiber_counter_id + 1)] = [comp_counter, iName];
- if (!interior.ingredients[iName].nbCurve) interior.ingredients[iName].nbCurve = 0;
- fiber_counter_id++;
- } else {
- cell.mapping_ids[counter_id] = [comp_counter, iName];
- if (!interior.ingredients[iName].results) { interior.ingredients[iName].results = []; }
- counter_id++;
- }
- }
- comp_counter++;
- }
- }
- }
- const { options } = cell;
- let resultsAsset: Asset.Wrapper<'binary'> | undefined;
- if (params.resultsFile) {
- resultsAsset = await plugin.runTask(plugin.managers.asset.resolve(params.resultsFile, 'binary', true));
- } else if (options?.resultfile) {
- const url = `${params.baseUrl}/results/${options.resultfile}`;
- resultsAsset = await plugin.runTask(plugin.managers.asset.resolve(Asset.getUrlAsset(plugin.managers.asset, url), 'binary', true));
- }
- if (resultsAsset) {
- (cache as any).asset = resultsAsset;
- const results = resultsAsset.data;
- // flip the byte order if needed
- const buffer = IsNativeEndianLittle ? results.buffer : flipByteOrder(results, 4);
- const numbers = new DataView(buffer);
- const ninst = getFloatValue(numbers, 0);
- const npoints = getFloatValue(numbers, 4);
- const ncurve = getFloatValue(numbers, 8);
- let offset = 12;
- if (ninst !== 0) {
- const pos = new Float32Array(buffer, offset, ninst * 4);
- offset += ninst * 4 * 4;
- const quat = new Float32Array(buffer, offset, ninst * 4);
- offset += ninst * 4 * 4;
- for (let i = 0; i < ninst; i++) {
- const x: number = pos[i * 4 + 0];
- const y: number = pos[i * 4 + 1];
- const z: number = pos[i * 4 + 2];
- const ingr_id = pos[i * 4 + 3] as number;
- const pid = cell.mapping_ids![ingr_id];
- if (!packings[pid[0]].ingredients[pid[1]].results) {
- packings[pid[0]].ingredients[pid[1]].results = [];
- }
- packings[pid[0]].ingredients[pid[1]].results.push([Vec3.create(x, y, z),
- Quat.create(quat[i * 4 + 0], quat[i * 4 + 1], quat[i * 4 + 2], quat[i * 4 + 3])]);
- }
- }
- if (npoints !== 0) {
- const ctr_pos = new Float32Array(buffer, offset, npoints * 4);
- offset += npoints * 4 * 4;
- offset += npoints * 4 * 4;
- const ctr_info = new Float32Array(buffer, offset, npoints * 4);
- offset += npoints * 4 * 4;
- const curve_ids = new Float32Array(buffer, offset, ncurve * 4);
- offset += ncurve * 4 * 4;
- let counter = 0;
- let ctr_points: Vec3[] = [];
- let prev_ctype = 0;
- let prev_cid = 0;
- for (let i = 0; i < npoints; i++) {
- const x: number = -ctr_pos[i * 4 + 0];
- const y: number = ctr_pos[i * 4 + 1];
- const z: number = ctr_pos[i * 4 + 2];
- const cid: number = ctr_info[i * 4 + 0]; // curve id
- const ctype: number = curve_ids[cid * 4 + 0]; // curve type
- // cid 148 165 -1 0
- // console.log("cid ",cid,ctype,prev_cid,prev_ctype);//165,148
- if (prev_ctype !== ctype) {
- const pid = cell.mapping_ids![-prev_ctype - 1];
- const cname = `curve${counter}`;
- packings[pid[0]].ingredients[pid[1]].nbCurve = counter + 1;
- packings[pid[0]].ingredients[pid[1]][cname] = ctr_points;
- ctr_points = [];
- counter = 0;
- } else if (prev_cid !== cid) {
- ctr_points = [];
- const pid = cell.mapping_ids![-prev_ctype - 1];
- const cname = `curve${counter}`;
- packings[pid[0]].ingredients[pid[1]][cname] = ctr_points;
- counter += 1;
- }
- ctr_points.push(Vec3.create(x, y, z));
- prev_ctype = ctype;
- prev_cid = cid;
- }
- // do the last one
- const pid = cell.mapping_ids![-prev_ctype - 1];
- const cname = `curve${counter}`;
- packings[pid[0]].ingredients[pid[1]].nbCurve = counter + 1;
- packings[pid[0]].ingredients[pid[1]][cname] = ctr_points;
- }
- }
- return new CellPack({ cell, packings });
- });
- },
- dispose({ cache }) {
- ((cache as any)?.asset as Asset.Wrapper | undefined)?.dispose();
- },
- });
- export { StructureFromCellpack };
- type StructureFromCellpack = typeof ParseCellPack
- const StructureFromCellpack = PluginStateTransform.BuiltIn({
- name: 'structure-from-cellpack',
- display: { name: 'Structure from CellPack', description: 'Create Structure from CellPack Packing' },
- from: CellPack,
- to: PSO.Molecule.Structure,
- params: a => {
- const options = a ? a.data.packings.map((d, i) => [i, d.name] as const) : [];
- return {
- packing: PD.Select(0, options),
- baseUrl: PD.Text(DefaultCellPackBaseUrl),
- ingredientFiles: PD.FileList({ accept: '.cif,.bcif,.pdb' })
- };
- }
- })({
- apply({ a, params, cache }, plugin: PluginContext) {
- return Task.create('Structure from CellPack', async ctx => {
- const packing = a.data.packings[params.packing];
- const ingredientFiles: IngredientFiles = {};
- if (params.ingredientFiles !== null) {
- for (const file of params.ingredientFiles) {
- ingredientFiles[file.name] = file;
- }
- }
- const { structure, assets, colors } = await createStructureFromCellPack(plugin, packing, params.baseUrl, ingredientFiles).runInContext(ctx);
- await CellPackInfoProvider.attach({ runtime: ctx, assetManager: plugin.managers.asset }, structure, {
- info: { packingsCount: a.data.packings.length, packingIndex: params.packing, colors }
- });
- (cache as any).assets = assets;
- return new PSO.Molecule.Structure(structure, { label: packing.name + '.' + packing.location });
- });
- },
- dispose({ b, cache }) {
- const assets = (cache as any).assets as Asset.Wrapper[];
- if (assets) {
- for (const a of assets) a.dispose();
- }
- if (b) {
- b.data.customPropertyDescriptors.dispose();
- for (const m of b.data.models) {
- m.customProperties.dispose();
- }
- }
- }
- });
- export { StructureFromAssemblies };
- type StructureFromAssemblies = typeof StructureFromAssemblies
- const StructureFromAssemblies = PluginStateTransform.BuiltIn({
- name: 'Structure from all assemblies',
- display: { name: 'Structure from all assemblies' },
- from: PSO.Molecule.Model,
- to: PSO.Molecule.Structure,
- params: {
- }
- })({
- canAutoUpdate({ newParams }) {
- return true;
- },
- apply({ a, params }) {
- return Task.create('Build Structure', async ctx => {
- // TODO: optimze
- // TODO: think of ways how to fast-track changes to this for animations
- const model = a.data;
- const initial_structure = Structure.ofModel(model);
- const structures: Structure[] = [];
- let structure: Structure = initial_structure;
- // the list of asambly *?
- const symmetry = ModelSymmetry.Provider.get(model);
- if (symmetry && symmetry.assemblies.length !== 0) {
- for (const a of symmetry.assemblies) {
- const s = await StructureSymmetry.buildAssembly(initial_structure, a.id).runInContext(ctx);
- structures.push(s);
- }
- const builder = Structure.Builder({ label: 'Membrane' });
- let offsetInvariantId = 0;
- for (const s of structures) {
- let maxInvariantId = 0;
- for (const u of s.units) {
- const invariantId = u.invariantId + offsetInvariantId;
- if (u.invariantId > maxInvariantId) maxInvariantId = u.invariantId;
- builder.addUnit(u.kind, u.model, u.conformation.operator, u.elements, Unit.Trait.None, invariantId);
- }
- offsetInvariantId += maxInvariantId + 1;
- }
- structure = builder.getStructure();
- for (let i = 0, il = structure.models.length; i < il; ++i) {
- Model.TrajectoryInfo.set(structure.models[i], { size: il, index: i });
- }
- }
- return new PSO.Molecule.Structure(structure, { label: a.label, description: `${a.description}` });
- });
- },
- dispose({ b }) {
- b?.data.customPropertyDescriptors.dispose();
- }
- });
- const CreateTransformer = StateTransformer.builderFactory('cellPACK');
- export const CreateCompartmentSphere = CreateTransformer({
- name: 'create-compartment-sphere',
- display: 'CompartmentSphere',
- from: PSO.Root, // or whatever data source
- to: PSO.Shape.Representation3D,
- params: {
- center: PD.Vec3(Vec3()),
- radius: PD.Numeric(1),
- label: PD.Text(`Compartment Sphere`)
- }
- })({
- canAutoUpdate({ oldParams, newParams }) {
- return true;
- },
- apply({ a, params }, plugin: PluginContext) {
- return Task.create('Compartment Sphere', async ctx => {
- const data = params;
- const repr = MBRepresentation({ webgl: plugin.canvas3d?.webgl, ...plugin.representation.structure.themes }, () => (MBParams));
- await repr.createOrUpdate({ ...params, quality: 'custom', xrayShaded: true, doubleSided: true }, data).runInContext(ctx);
- return new PSO.Shape.Representation3D({ repr, sourceData: a }, { label: data.label });
- });
- }
- });
|