From f1d78e48057124665f9689ec3809881c84e86022 Mon Sep 17 00:00:00 2001 From: "DESKTOP-O6LIMN9\\ludov" <ludovic.autin@gmail.com> Date: Sat, 11 Apr 2020 14:13:43 +0200 Subject: [PATCH] support for membrane in list files and on the server if available as bcif clean the console.log --- README.md | 6 +- src/apps/viewer/extensions/cellpack/curve.ts | 5 - src/apps/viewer/extensions/cellpack/model.ts | 153 ++++++++++++++++--- 3 files changed, 133 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 5b5ead33d..4da71bf2e 100644 --- a/README.md +++ b/README.md @@ -114,9 +114,9 @@ and navigate to `build/viewer` **Convert any CIF to BinaryCIF** - node build/model-server/preprocess -i file.cif -ob file.bcif - -To see all available commands, use ``node build/model-server/preprocess -h``. + node lib/servers/model/preprocess -i file.cif -ob file.bcif + +To see all available commands, use ``node lib/servers/model/preprocess -h``. Or diff --git a/src/apps/viewer/extensions/cellpack/curve.ts b/src/apps/viewer/extensions/cellpack/curve.ts index 0428f46c8..4b789f7a5 100644 --- a/src/apps/viewer/extensions/cellpack/curve.ts +++ b/src/apps/viewer/extensions/cellpack/curve.ts @@ -192,7 +192,6 @@ function GetMiniFrame(points: Vec3[], normals: Vec3[]) { const rpTmpVec1 = Vec3() export function getMatFromResamplePoints(points: NumberArray, segmentLength: number) { - //const segmentLength = 3.4 const new_points = ResampleControlPoints(points, segmentLength) const npoints = new_points.length const new_normal = GetSmoothNormals(new_points) @@ -200,10 +199,6 @@ export function getMatFromResamplePoints(points: NumberArray, segmentLength: num const limit = npoints const transforms: Mat4[] = [] const pti = Vec3.copy(rpTmpVec1, new_points[0]); - // console.log(new_points.length) - // console.log(points.length/3) - // console.log(limit) - // console.log(segmentLength) for (let i = 0; i<npoints-2; ++i) { const pti1: Vec3 = new_points[i+1] // Vec3.create(points[(i+1)*3],points[(i+1)*3+1],points[(i+1)*3+2]); const d = Vec3.distance(pti, pti1) diff --git a/src/apps/viewer/extensions/cellpack/model.ts b/src/apps/viewer/extensions/cellpack/model.ts index e43e7e514..539c36530 100644 --- a/src/apps/viewer/extensions/cellpack/model.ts +++ b/src/apps/viewer/extensions/cellpack/model.ts @@ -8,7 +8,7 @@ import { StateAction, StateBuilder, StateTransformer, State } from '../../../../ import { PluginContext } from '../../../../mol-plugin/context'; import { PluginStateObject as PSO } from '../../../../mol-plugin-state/objects'; import { ParamDefinition as PD } from '../../../../mol-util/param-definition'; -import { Ingredient, CellPacking } from './data'; +import { Ingredient, IngredientSource, CellPacking } from './data'; import { getFromPdb, getFromCellPackDB, IngredientFiles, parseCif, parsePDBfile } from './util'; import { Model, Structure, StructureSymmetry, StructureSelection, QueryContext, Unit } from '../../../../mol-model/structure'; import { trajectoryFromMmCIF, MmcifFormat } from '../../../../mol-model-formats/structure/mmcif'; @@ -34,44 +34,56 @@ function getCellPackModelUrl(fileName: string, baseUrl: string) { return `${baseUrl}/results/${fileName}` } -async function getModel(id: string, baseUrl: string, file?: File) { +async function getModel(id: string, model_id:number, baseUrl: string, file?: File) { let model: Model; if (file) { const text = await file.text() if (file.name.endsWith('.cif')) { const cif = (await parseCif(text)).blocks[0] - model = (await trajectoryFromMmCIF(cif).run())[0] + model = (await trajectoryFromMmCIF(cif).run())[model_id] } else if (file.name.endsWith('.pdb')) { const pdb = await parsePDBfile(text, id) - model = (await trajectoryFromPDB(pdb).run())[0] + model = (await trajectoryFromPDB(pdb).run())[model_id] } else { throw new Error(`unsupported file type '${file.name}'`) } } else if (id.match(/^[1-9][a-zA-Z0-9]{3,3}$/i)) { // return const cif = await getFromPdb(id) - model = (await trajectoryFromMmCIF(cif).run())[0] + model = (await trajectoryFromMmCIF(cif).run())[model_id] } else { const pdb = await getFromCellPackDB(id, baseUrl) - model = (await trajectoryFromPDB(pdb).run())[0] + model = (await trajectoryFromPDB(pdb).run())[model_id] } return model } -async function getStructure(model: Model, props: { assembly?: string } = {}) { +async function getStructure(model: Model, source:IngredientSource,props: { assembly?: string } = {}) { let structure = Structure.ofModel(model) const { assembly } = props if (assembly) { structure = await StructureSymmetry.buildAssembly(structure, assembly).run() } + let query; + if (source.selection){ + const asymIds:string[] = source.selection.replace(" :","").split(" or") + query = MS.struct.modifier.union([ + MS.struct.generator.atomGroups({ + 'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer']), + 'chain-test': MS.core.set.has([MS.set(...asymIds), MS.ammp('auth_asym_id')]) + }) + ]) + } + else { + query = MS.struct.modifier.union([ + MS.struct.generator.atomGroups({ + 'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer']) + }) + ]) + } - const query = MS.struct.modifier.union([ - MS.struct.generator.atomGroups({ - 'entity-test': MS.core.rel.eq([MS.ammp('entityType'), 'polymer']) - }) - ]) const compiled = compile<StructureSelection>(query) const result = compiled(new QueryContext(structure)) structure = StructureSelection.unionStructure(result) @@ -79,7 +91,7 @@ async function getStructure(model: Model, props: { assembly?: string } = {}) { return structure } -function getTransform(trans: Vec3, rot: Quat) { +function getTransformLegacy(trans: Vec3, rot: Quat) { const q: Quat = Quat.create(-rot[3], rot[0], rot[1], rot[2]) const m: Mat4 = Mat4.fromQuat(Mat4.zero(), q) Mat4.transpose(m, m) @@ -88,14 +100,24 @@ function getTransform(trans: Vec3, rot: Quat) { return m } -function getResultTransforms(results: Ingredient['results']) { - return results.map((r: Ingredient['results'][0]) => getTransform(r[0], r[1])) +function getTransform(trans: Vec3, rot: Quat) { + const q: Quat = Quat.create(rot[0], rot[1], rot[2], rot[3]) + const m: Mat4 = Mat4.fromQuat(Mat4.zero(), q) + const p: Vec3 = Vec3.create(trans[0],trans[1],trans[2]) + Mat4.setTranslation(m, p) + return m +} + + +function getResultTransforms(results: Ingredient['results'],legacy:boolean) { + if (legacy) return results.map((r: Ingredient['results'][0]) => getTransformLegacy(r[0], r[1])) + else return results.map((r: Ingredient['results'][0]) => getTransform(r[0], r[1])) } function getCurveTransforms(ingredient: Ingredient) { const n = ingredient.nbCurve || 0 const instances: Mat4[] = [] - + const segmentLength = (ingredient.radii)? ((ingredient.radii[0].radii)?ingredient.radii[0].radii[0]*2.0:3.4):3.4; for (let i = 0; i < n; ++i) { const cname = `curve${i}` if (!(cname in ingredient)) { @@ -109,7 +131,7 @@ function getCurveTransforms(ingredient: Ingredient) { } const points = new Float32Array(_points.length * 3) for (let i = 0, il = _points.length; i < il; ++i) Vec3.toArray(_points[i], points, i * 3) - const newInstances = getMatFromResamplePoints(points) + const newInstances = getMatFromResamplePoints(points,segmentLength) instances.push(...newInstances) } @@ -224,7 +246,7 @@ function getCifCurve(name: string, transforms: Mat4[], model: Model) { }; } -async function getCurve(name: string, transforms: Mat4[], model: Model) { +async function getCurve(name: string, ingredient:Ingredient, transforms: Mat4[], model: Model) { const cif = getCifCurve(name, transforms, model) const curveModelTask = Task.create('Curve Model', async ctx => { @@ -234,7 +256,7 @@ async function getCurve(name: string, transforms: Mat4[], model: Model) { }) const curveModel = await curveModelTask.run() - return getStructure(curveModel) + return getStructure(curveModel, ingredient.source) } async function getIngredientStructure(ingredient: Ingredient, baseUrl: string, ingredientFiles: IngredientFiles) { @@ -251,14 +273,55 @@ async function getIngredientStructure(ingredient: Ingredient, baseUrl: string, i if (name === 'lypoglycane') return } - const model = await getModel(source.pdb || name, baseUrl, file) + //model id in case structure is NMR + const model_id = (ingredient.source.model)? parseInt(ingredient.source.model) : 0; + const model = await getModel(source.pdb || name,model_id, baseUrl, file) if (!model) return if (nbCurve) { - return getCurve(name, getCurveTransforms(ingredient), model) + return getCurve(name, ingredient, getCurveTransforms(ingredient), model) } else { - const structure = await getStructure(model, { assembly: source.biomt ? '1' : undefined }) - return getAssembly(getResultTransforms(results), structure) + let bu:string|undefined = source.bu ? source.bu : undefined; + if (bu){ + if (bu === "AU") {bu = undefined;} + else { + bu = bu.slice(2) + } + } + let structure = await getStructure(model,source, { assembly: bu }) + //transform with offset and pcp + let legacy:boolean = true + if (ingredient.offset || ingredient.principalAxis) + //center the structure + { + legacy=false + const boundary = structure.boundary + let structureCenter:Vec3 = Vec3.zero() + Vec3.negate(structureCenter,boundary.sphere.center) + const m1: Mat4 = Mat4.identity() + Mat4.setTranslation(m1, structureCenter) + structure = Structure.transform(structure,m1) + if (ingredient.offset) + { + if (!Vec3.exactEquals(ingredient.offset,Vec3.zero())) + { + const m: Mat4 = Mat4.identity(); + Mat4.setTranslation(m, ingredient.offset) + structure = Structure.transform(structure,m); + } + } + if (ingredient.principalAxis) + { + if (!Vec3.exactEquals(ingredient.principalAxis,Vec3.unitZ)) + { + const q: Quat = Quat.identity(); + Quat.rotationTo(q,ingredient.principalAxis,Vec3.unitZ) + const m: Mat4 = Mat4.fromQuat(Mat4.zero(), q) + structure = Structure.transform(structure,m); + } + } + } + return getAssembly(getResultTransforms(results,legacy), structure) } } @@ -319,6 +382,46 @@ async function handleHivRna(ctx: { runtime: RuntimeContext, fetch: AjaxTask }, p } } +async function loadMembrane(name:string, plugin: PluginContext, runtime: RuntimeContext, state: State, params: LoadCellPackModelParams) { + const fname: string = `${name}.bcif` + let ingredientFiles: IngredientFiles = {} + if (params.ingredients.files !== null) { + for (let i = 0, il = params.ingredients.files.length; i < il; ++i) { + const file = params.ingredients.files.item(i) + if (file) ingredientFiles[file.name] = file + } + } + const url = `${params.baseUrl}/membranes/${name}.bcif` + // + const file = (ingredientFiles)?ingredientFiles[fname]:null; + let membrane + if (!file) + //can we check if url exist + { + membrane = await state.build().toRoot() + .apply(StateTransforms.Data.Download, { label: name, url, isBinary: true }, { state: { isGhost: true } }) + .apply(StateTransforms.Data.ParseCif, undefined, { state: { isGhost: true } }) + .apply(StateTransforms.Model.TrajectoryFromMmCif, undefined, { state: { isGhost: true } }) + .apply(StateTransforms.Model.ModelFromTrajectory, undefined, { state: { isGhost: true } }) + .apply(StateTransforms.Model.StructureFromModel) + .commit() + } + else { + membrane = await state.build().toRoot() + .apply(StateTransforms.Data.ReadFile, { file, isBinary: true, label: file.name }, { state: { isGhost: true } }) + .apply(StateTransforms.Data.ParseCif, undefined, { state: { isGhost: true } }) + .apply(StateTransforms.Model.TrajectoryFromMmCif, undefined, { state: { isGhost: true } }) + .apply(StateTransforms.Model.ModelFromTrajectory, undefined, { state: { isGhost: true } }) + .apply(StateTransforms.Model.StructureFromModel) + .commit() + } + + const membraneParams = { + representation: params.preset.representation, + } + await CellpackMembranePreset.apply(membrane, membraneParams, plugin) +} + async function loadHivMembrane(plugin: PluginContext, runtime: RuntimeContext, state: State, params: LoadCellPackModelParams) { const url = `${params.baseUrl}/membranes/hiv_lipids.bcif` const membrane = await state.build().toRoot() @@ -381,6 +484,9 @@ async function loadPackings(plugin: PluginContext, runtime: RuntimeContext, stat representation: params.preset.representation, } await CellpackPackingPreset.apply(packing, packingParams, plugin) + if ( packings[i].location === "surface" ){ + await loadMembrane(packings[i].name, plugin, runtime, state, params) + } } } @@ -392,6 +498,7 @@ const LoadCellPackModelParams = { ['HIV-1_0.1.6-8_mixed_radii_pdb.cpr', 'HIV-1_0.1.6-8_mixed_radii_pdb'], ['hiv_lipids.bcif', 'hiv_lipids'], ['influenza_model1.json', 'influenza_model1'], + ['ExosomeModel.json', 'ExosomeModel'], ['Mycoplasma1.5_mixed_pdb_fixed.cpr', 'Mycoplasma1.5_mixed_pdb_fixed'], ] as const), 'file': PD.File({ accept: 'id' }), -- GitLab