Skip to content
Snippets Groups Projects
Commit ca825d72 authored by ludovic autin's avatar ludovic autin
Browse files

binary model loading support, latest mycoplasma model.

parent f833efae
No related branches found
No related tags found
No related merge requests found
...@@ -122,9 +122,9 @@ and navigate to `build/viewer` ...@@ -122,9 +122,9 @@ and navigate to `build/viewer`
**Convert any CIF to BinaryCIF** **Convert any CIF to BinaryCIF**
node lib/servers/model/preprocess -i file.cif -ob file.bcif node lib/commonjs/servers/model/preprocess -i file.cif -ob file.bcif
To see all available commands, use ``node lib/servers/model/preprocess -h``. To see all available commands, use ``node lib/commonjs/servers/model/preprocess -h``.
Or Or
......
...@@ -15,6 +15,7 @@ export interface CellPacking { ...@@ -15,6 +15,7 @@ export interface CellPacking {
name: string, name: string,
location: 'surface' | 'interior' | 'cytoplasme', location: 'surface' | 'interior' | 'cytoplasme',
ingredients: Packing['ingredients'] ingredients: Packing['ingredients']
mb?: Membrane
} }
// //
...@@ -23,6 +24,7 @@ export interface Cell { ...@@ -23,6 +24,7 @@ export interface Cell {
recipe: Recipe recipe: Recipe
cytoplasme?: Packing cytoplasme?: Packing
compartments?: { [key: string]: Compartment } compartments?: { [key: string]: Compartment }
mapping_ids?: { [key: number]: [number,string] }
} }
export interface Recipe { export interface Recipe {
...@@ -35,6 +37,12 @@ export interface Recipe { ...@@ -35,6 +37,12 @@ export interface Recipe {
export interface Compartment { export interface Compartment {
surface?: Packing surface?: Packing
interior?: Packing interior?: Packing
mb?: Membrane
}
export interface Membrane{
positions: number[];
radii: number[];
} }
export interface Packing { export interface Packing {
...@@ -64,11 +72,13 @@ export interface Ingredient { ...@@ -64,11 +72,13 @@ export interface Ingredient {
[curveX: string]: unknown; [curveX: string]: unknown;
/** the orientation in the membrane */ /** the orientation in the membrane */
principalAxis?: Vec3; principalAxis?: Vec3;
principalVector?: Vec3;
/** offset along membrane */ /** offset along membrane */
offset?: Vec3; offset?: Vec3;
ingtype?: string; ingtype?: string;
color?: Vec3; color?: Vec3;
confidence?: number; confidence?: number;
Type?: string;
} }
export interface IngredientSource { export interface IngredientSource {
......
This diff is collapsed.
...@@ -9,8 +9,8 @@ import { StructureRepresentationPresetProvider, presetStaticComponent } from '.. ...@@ -9,8 +9,8 @@ import { StructureRepresentationPresetProvider, presetStaticComponent } from '..
import { ParamDefinition as PD } from '../../mol-util/param-definition'; import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { ColorNames } from '../../mol-util/color/names'; import { ColorNames } from '../../mol-util/color/names';
import { CellPackGenerateColorThemeProvider } from './color/generate'; import { CellPackGenerateColorThemeProvider } from './color/generate';
import { CellPackInfoProvider } from './property'; //import { CellPackInfoProvider } from './property';
import { CellPackProvidedColorThemeProvider } from './color/provided'; //import { CellPackProvidedColorThemeProvider } from './color/provided';
export const CellpackPackingPresetParams = { export const CellpackPackingPresetParams = {
traceOnly: PD.Boolean(true), traceOnly: PD.Boolean(true),
...@@ -42,8 +42,9 @@ export const CellpackPackingPreset = StructureRepresentationPresetProvider({ ...@@ -42,8 +42,9 @@ export const CellpackPackingPreset = StructureRepresentationPresetProvider({
Object.assign(reprProps, { sizeFactor: 2 }); Object.assign(reprProps, { sizeFactor: 2 });
} }
const info = structureCell.obj?.data && CellPackInfoProvider.get(structureCell.obj?.data).value; //const info = structureCell.obj?.data && CellPackInfoProvider.get(structureCell.obj?.data).value;
const color = info?.colors ? CellPackProvidedColorThemeProvider.name : CellPackGenerateColorThemeProvider.name; //default is generated
const color = CellPackGenerateColorThemeProvider.name;//info?.colors ? CellPackProvidedColorThemeProvider.name : CellPackGenerateColorThemeProvider.name;
const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, {}); const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, {});
const representations = { const representations = {
......
/**
* Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ShapeRepresentation } from '../../mol-repr/shape/representation';
import { Shape } from '../../mol-model/shape';
import { ColorNames } from '../../mol-util/color/names';
import { RuntimeContext } from '../../mol-task';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Mesh } from '../../mol-geo/geometry/mesh/mesh';
import { MeshBuilder } from '../../mol-geo/geometry/mesh/mesh-builder';
import { Polyhedron, DefaultPolyhedronProps } from '../../mol-geo/primitive/polyhedron';
import { Icosahedron } from '../../mol-geo/primitive/Icosahedron';
import { Mat4, Vec3 } from '../../mol-math/linear-algebra';
import { RepresentationParamsGetter, Representation, RepresentationContext } from '../../mol-repr/representation';
interface MembraneSphereData {
radius: number
center: Vec3
}
const MembraneSphereParams = {
...Mesh.Params,
cellColor: PD.Color(ColorNames.orange),
cellScale: PD.Numeric(2, { min: 0.1, max: 5, step: 0.1 }),
radius: PD.Numeric(2, { min: 0.1, max: 5, step: 0.1 }),
center: PD.Vec3(Vec3.create(0,0,0)),
quality: { ...Mesh.Params.quality, isEssential: false },
};
type MeshParams = typeof MembraneSphereParams
const MembraneSphereVisuals = {
'mesh': (ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneSphereData, MeshParams>) => ShapeRepresentation(getMBShape, Mesh.Utils),
};
export const MBParams = {
...MembraneSphereParams
};
export type MBParams = typeof MBParams
export type UnitcellProps = PD.Values<MBParams>
function getMBMesh(data: MembraneSphereData, props: UnitcellProps, mesh?: Mesh) {
const state = MeshBuilder.createState(256, 128, mesh);
const radius = props.radius;
var p = DefaultPolyhedronProps;
p.detail = 3;
p.radius = radius;
const { vertices, indices } = Icosahedron();
const asphere = Polyhedron(vertices, indices, p);
//const asphere = Sphere(3);
var trans:Mat4 = Mat4.identity();
//Mat4.fromScaling(trans, Vec3.create(radius,radius,radius));
state.currentGroup = 1;
MeshBuilder.addPrimitive(state, trans, asphere);
const m = MeshBuilder.getMesh(state);
return m;
}
function getMBShape(ctx: RuntimeContext, data: MembraneSphereData, props: UnitcellProps, shape?: Shape<Mesh>) {
const geo = getMBMesh(data, props, shape && shape.geometry);
const label = "mb";
return Shape.create(label, data, geo, () => props.cellColor, () => 1, () => label);
}
//
/*
export function getMBData(model: Model, symmetry: Symmetry, props: UnitcellProps) {
const ref = Vec3();
if (props.ref === 'model') {
Vec3.transformMat4(ref, Model.getCenter(model), symmetry.spacegroup.cell.toFractional);
}
return { symmetry, ref };
}
*/
export type MBRepresentation = Representation<MembraneSphereData, MBParams>
export function MBRepresentation(ctx: RepresentationContext, getParams: RepresentationParamsGetter<MembraneSphereData, MBParams>): MBRepresentation {
return Representation.createMulti('MB', ctx, getParams, Representation.StateBuilder, MembraneSphereVisuals as unknown as Representation.Def<MembraneSphereData, MBParams>);
}
\ No newline at end of file
...@@ -9,15 +9,19 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition'; ...@@ -9,15 +9,19 @@ import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { Task } from '../../mol-task'; import { Task } from '../../mol-task';
import { CellPack as _CellPack, Cell, CellPacking } from './data'; import { CellPack as _CellPack, Cell, CellPacking } from './data';
import { createStructureFromCellPack } from './model'; import { createStructureFromCellPack } from './model';
import { IngredientFiles } from './util'; import { IngredientFiles, getFloatValue } from './util';
import { Asset } from '../../mol-util/assets'; import { Asset } from '../../mol-util/assets';
import { PluginContext } from '../../mol-plugin/context'; import { PluginContext } from '../../mol-plugin/context';
import { CellPackInfoProvider } from './property'; import { CellPackInfoProvider } from './property';
import { Structure, StructureSymmetry, Unit, Model } from '../../mol-model/structure'; import { Structure, StructureSymmetry, Unit, Model } from '../../mol-model/structure';
import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry'; import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
import { Vec3, Quat } from '../../mol-math/linear-algebra';
import { readFromFile } from '../../mol-util/data-source';
import { StateTransformer } from '../../mol-state';
import { MBRepresentation, MBParams } from './representation';
export const DefaultCellPackBaseUrl = 'https://mesoscope.scripps.edu/data/cellPACK_data/cellPACK_database_1.1.0/'; //export const DefaultCellPackBaseUrl = 'https://mesoscope.scripps.edu/data/cellPACK_data/cellPACK_database_1.1.0/';
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 class CellPack extends PSO.Create<_CellPack>({ name: 'CellPack', typeClass: 'Object' }) { }
export { ParseCellPack }; export { ParseCellPack };
...@@ -26,23 +30,178 @@ const ParseCellPack = PluginStateTransform.BuiltIn({ ...@@ -26,23 +30,178 @@ const ParseCellPack = PluginStateTransform.BuiltIn({
name: 'parse-cellpack', name: 'parse-cellpack',
display: { name: 'Parse CellPack', description: 'Parse CellPack from JSON data' }, display: { name: 'Parse CellPack', description: 'Parse CellPack from JSON data' },
from: PSO.Format.Json, from: PSO.Format.Json,
to: CellPack to: CellPack,
params: a => {
return {
modeFile: PD.File({ accept: '.bin' })
};
}
})({ })({
apply({ a }) { apply({a, params}) {
return Task.create('Parse CellPack', async ctx => { return Task.create('Parse CellPack', async ctx => {
const cell = a.data as Cell; const cell = a.data as Cell;
let counter_id = 0;
let fiber_counter_id = 0;
let comp_counter = 0;
const packings: CellPacking[] = []; const packings: CellPacking[] = [];
const { compartments, cytoplasme } = cell; const { compartments, cytoplasme } = cell;
let iName = "";
if(!cell.mapping_ids)cell.mapping_ids={};
if (cytoplasme) {
packings.push({ name: 'Cytoplasme', location: 'cytoplasme', ingredients: cytoplasme.ingredients });
for (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) { if (compartments) {
for (const name in compartments) { for (const name in compartments) {
const { surface, interior } = compartments[name]; const { surface, interior } = compartments[name];
if (surface) packings.push({ name, location: 'surface', ingredients: surface.ingredients }); if (surface) {
if (interior) packings.push({ name, location: 'interior', ingredients: interior.ingredients }); packings.push({ name, location: 'surface', ingredients: surface.ingredients, mb: compartments[name].mb });
for (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) {
packings.push({ name, location: 'interior', ingredients: interior.ingredients });
for (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++;
}
}
}
if (params.modeFile && params.modeFile.file){
const model_data = await readFromFile(params.modeFile.file, 'binary').runInContext(ctx);//async ?
var numbers = new DataView(model_data.buffer);
var ninst = getFloatValue(numbers,0);
var npoints = getFloatValue(numbers,4);
var ncurve = getFloatValue(numbers,8);
/*
console.log("Parse CellPack");
console.log("ninst ",ninst);
console.log("npoints ",npoints);
console.log("ncurve ",ncurve);
*/
let pos = new Float32Array();
let quat = new Float32Array();
let ctr_pos = new Float32Array();
//let ctr_norm = new Float32Array();
let ctr_info = new Float32Array();
let curve_ids = new Float32Array();
//let ctrl_pts= new Float32Array();
//let ctrl_normal= new Float32Array();
//let ctrl_info= new Float32Array();//#curve_id, curve_type, angle, uLength
let offset = 12;
if (ninst !== 0){
pos = new Float32Array(model_data.buffer,offset,ninst*4);offset+=ninst*4*4;
quat = new Float32Array(model_data.buffer,offset,ninst*4);offset+=ninst*4*4;
}
if ( npoints != 0 )
{
ctr_pos = new Float32Array(model_data.buffer,offset,npoints*4);offset+=npoints*4*4;
//ctr_norm = new Float32Array(model_data,offset,ncurve*4);
offset+=npoints*4*4;
ctr_info = new Float32Array(model_data.buffer,offset,npoints*4);offset+=npoints*4*4;
curve_ids = new Float32Array(model_data.buffer,offset,ncurve*4);offset+=ncurve*4*4;
}
//data_from_buffer = {"pos":pos,"quat":quat,"ctrl_pts":ctrl_pts,"ctrl_normal":ctrl_normal,"ctrl_info":ctrl_info};
//create all the bodys then the instance ?
for (var i=0;i<ninst;i++)
{
let x:number = pos[i*4+0];
let y:number = pos[i*4+1];
let z:number = pos[i*4+2];
//q = new THREE.Quaternion(quats[i*4+0],quats[i*4+1],quats[i*4+2],quats[i*4+3]);
let ingr_id = pos[i*4+3] as number;
let 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])]);
}
let counter = 0;
let ctr_points:Vec3[] = [];
let prev_ctype = 0;
let prev_cid = 0;
/*
console.log("ctr_info",ctr_info);
console.log("curve_ids",curve_ids);
*/
for (var i=0;i<npoints;i++)
{
let x:number = -ctr_pos[i*4+0];
let y:number = ctr_pos[i*4+1];
let z:number = ctr_pos[i*4+2];
let cid:number = ctr_info[i*4+0];//curve id
let 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){
let pid = cell.mapping_ids[-prev_ctype-1];
const cname = `curve${counter}`;
//console.log("ctype ",pid,cname,prev_ctype,(-prev_ctype-1));
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 = [];
let pid = cell.mapping_ids[-prev_ctype-1];
const cname = `curve${counter}`;
//console.log("cid ",pid,cname,prev_ctype,(-prev_ctype-1),prev_cid,cid);
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
if ( npoints != 0 )
{
let pid = cell.mapping_ids[-prev_ctype-1];
const cname = `curve${counter}`;
//console.log("ctype ",pid,cname,prev_ctype,(-prev_ctype-1));
packings[pid[0]].ingredients[pid[1]].nbCurve = counter+1;
packings[pid[0]].ingredients[pid[1]][cname] = ctr_points;
ctr_points = [];
}
counter = 0;
//console.log("done");
//console.log(packings);
} }
if (cytoplasme) packings.push({ name: 'Cytoplasme', location: 'cytoplasme', ingredients: cytoplasme.ingredients });
return new CellPack({ cell, packings }); return new CellPack({ cell, packings });
}); });
} }
...@@ -77,9 +236,8 @@ const StructureFromCellpack = PluginStateTransform.BuiltIn({ ...@@ -77,9 +236,8 @@ const StructureFromCellpack = PluginStateTransform.BuiltIn({
await CellPackInfoProvider.attach({ runtime: ctx, assetManager: plugin.managers.asset }, structure, { await CellPackInfoProvider.attach({ runtime: ctx, assetManager: plugin.managers.asset }, structure, {
info: { packingsCount: a.data.packings.length, packingIndex: params.packing, colors } info: { packingsCount: a.data.packings.length, packingIndex: params.packing, colors }
}); });
(cache as any).assets = assets; (cache as any).assets = assets;
return new PSO.Molecule.Structure(structure, { label: packing.name }); return new PSO.Molecule.Structure(structure, { label: packing.name+"."+packing.location });
}); });
}, },
dispose({ b, cache }) { dispose({ b, cache }) {
...@@ -125,7 +283,7 @@ const StructureFromAssemblies = PluginStateTransform.BuiltIn({ ...@@ -125,7 +283,7 @@ const StructureFromAssemblies = PluginStateTransform.BuiltIn({
const s = await StructureSymmetry.buildAssembly(initial_structure, a.id).runInContext(ctx); const s = await StructureSymmetry.buildAssembly(initial_structure, a.id).runInContext(ctx);
structures.push(s); structures.push(s);
} }
const builder = Structure.Builder(); const builder = Structure.Builder({ label: "Membrane" });
let offsetInvariantId = 0; let offsetInvariantId = 0;
for (const s of structures) { for (const s of structures) {
let maxInvariantId = 0; let maxInvariantId = 0;
...@@ -148,3 +306,28 @@ const StructureFromAssemblies = PluginStateTransform.BuiltIn({ ...@@ -148,3 +306,28 @@ const StructureFromAssemblies = PluginStateTransform.BuiltIn({
b?.data.customPropertyDescriptors.dispose(); b?.data.customPropertyDescriptors.dispose();
} }
}); });
const CreateTransformer = StateTransformer.builderFactory('cellPACK');
export const CreateSphere = CreateTransformer({
name: 'create-sphere',
display: 'Sphere',
from: PSO.Root, // or whatever data source
to: PSO.Shape.Representation3D,
params: {
center: PD.Vec3(Vec3()),
radius: PD.Numeric(1)
}
})({
canAutoUpdate({ oldParams, newParams }) {
return true;
},
apply({ a, params }, plugin: PluginContext) {
return Task.create('Custom Sphere', async ctx => {
const data = params;
const repr = MBRepresentation({ webgl: plugin.canvas3d?.webgl, ...plugin.representation.structure.themes }, () => (MBParams));
await repr.createOrUpdate({ ...params, quality: 'custom',doubleSided:true }, data).runInContext(ctx);
return new PSO.Shape.Representation3D({ repr, sourceData: a }, { label: `My Sphere` });
});
}
});
\ No newline at end of file
...@@ -37,7 +37,8 @@ async function downloadPDB(plugin: PluginContext, url: string, id: string, asset ...@@ -37,7 +37,8 @@ async function downloadPDB(plugin: PluginContext, url: string, id: string, asset
} }
export async function getFromPdb(plugin: PluginContext, pdbId: string, assetManager: AssetManager) { export async function getFromPdb(plugin: PluginContext, pdbId: string, assetManager: AssetManager) {
const { cif, asset } = await downloadCif(plugin, `https://models.rcsb.org/${pdbId.toUpperCase()}.bcif`, true, assetManager); //${pdbId.toUpperCase()}
const { cif, asset } = await downloadCif(plugin, `https://models.rcsb.org/${pdbId}.bcif`, true, assetManager);
return { mmcif: cif.blocks[0], asset }; return { mmcif: cif.blocks[0], asset };
} }
...@@ -75,3 +76,34 @@ export function getStructureMean(structure: Structure) { ...@@ -75,3 +76,34 @@ export function getStructureMean(structure: Structure) {
const { elementCount } = structure; const { elementCount } = structure;
return Vec3.create(xSum / elementCount, ySum / elementCount, zSum / elementCount); return Vec3.create(xSum / elementCount, ySum / elementCount, zSum / elementCount);
} }
export function getFloatValue(value: DataView, offset : number) {
// if the last byte is a negative value (MSB is 1), the final
// float should be too
const negative = value.getInt8(offset + 2) >>> 31;
// this is how the bytes are arranged in the byte array/DataView
// buffer
const [b0, b1, b2, exponent] = [
// get first three bytes as unsigned since we only care
// about the last 8 bits of 32-bit js number returned by
// getUint8().
// Should be the same as: getInt8(offset) & -1 >>> 24
value.getUint8(offset),
value.getUint8(offset + 1),
value.getUint8(offset + 2),
// get the last byte, which is the exponent, as a signed int
// since it's already correct
value.getInt8(offset + 3)
];
let mantissa = b0 | (b1 << 8) | (b2 << 16);
if (negative) {
// need to set the most significant 8 bits to 1's since a js
// number is 32 bits but our mantissa is only 24.
mantissa |= 255 << 24;
}
return mantissa * Math.pow(10, exponent);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment