浏览代码

cellpack, add support for local ingredient files

Alexander Rose 5 年之前
父节点
当前提交
373a69abbd

+ 33 - 16
src/apps/viewer/extensions/cellpack/model.ts

@@ -9,7 +9,7 @@ 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 { getFromPdb, getFromCellPackDB } from './util';
+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';
 import { trajectoryFromPDB } from '../../../../mol-model-formats/structure/pdb';
@@ -34,9 +34,21 @@ function getCellPackModelUrl(fileName: string, baseUrl: string) {
     return `${baseUrl}/results/${fileName}`
 }
 
-async function getModel(id: string, baseUrl: string) {
+async function getModel(id: string, baseUrl: string, file?: File) {
     let model: Model;
-    if (id.match(/^[1-9][a-zA-Z0-9]{3,3}$/i)) {
+    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]
+        } else if (file.name.endsWith('.pdb')) {
+            const pdb = await parsePDBfile(text, id)
+
+            model = (await trajectoryFromPDB(pdb).run())[0]
+        } 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]
@@ -225,19 +237,21 @@ async function getCurve(name: string, transforms: Mat4[], model: Model) {
     return getStructure(curveModel)
 }
 
-async function getIngredientStructure(ingredient: Ingredient, baseUrl: string) {
+async function getIngredientStructure(ingredient: Ingredient, baseUrl: string, ingredientFiles: IngredientFiles) {
     const { name, source, results, nbCurve } = ingredient
-
-    // TODO can these be added to the library?
-    if (name === 'HIV1_CAhex_0_1_0') return
-    if (name === 'HIV1_CAhexCyclophilA_0_1_0') return
-    if (name === 'iLDL') return
-    if (name === 'peptides') return
-    if (name === 'lypoglycane') return
-
     if (source.pdb === 'None') return
 
-    const model = await getModel(source.pdb || name, baseUrl)
+    const file = ingredientFiles[source.pdb]
+    if (!file) {
+        // TODO can these be added to the library?
+        if (name === 'HIV1_CAhex_0_1_0') return
+        if (name === 'HIV1_CAhexCyclophilA_0_1_0') return
+        if (name === 'iLDL') return
+        if (name === 'peptides') return
+        if (name === 'lypoglycane') return
+    }
+
+    const model = await getModel(source.pdb || name, baseUrl, file)
     if (!model) return
 
     if (nbCurve) {
@@ -248,13 +262,13 @@ async function getIngredientStructure(ingredient: Ingredient, baseUrl: string) {
     }
 }
 
-export function createStructureFromCellPack(packing: CellPacking, baseUrl: string) {
+export function createStructureFromCellPack(packing: CellPacking, baseUrl: string, ingredientFiles: IngredientFiles) {
     return Task.create('Create Packing Structure', async ctx => {
         const { ingredients, name } = packing
         const structures: Structure[] = []
         for (const iName in ingredients) {
             if (ctx.shouldUpdate) await ctx.update(iName)
-            const s = await getIngredientStructure(ingredients[iName], baseUrl)
+            const s = await getIngredientStructure(ingredients[iName], baseUrl, ingredientFiles)
             if (s) structures.push(s)
         }
 
@@ -345,7 +359,7 @@ async function loadPackings(plugin: PluginContext, runtime: RuntimeContext, stat
     await handleHivRna({ runtime, fetch: plugin.fetch }, packings, params.baseUrl)
 
     for (let i = 0, il = packings.length; i < il; ++i) {
-        const p = { packing: i, baseUrl: params.baseUrl }
+        const p = { packing: i, baseUrl: params.baseUrl, ingredientFiles: params.ingredients.files }
 
         const packing = state.build().to(cellPackBuilder.ref).apply(StructureFromCellpack, p)
         await plugin.updateDataState(packing, { revertOnError: true });
@@ -378,6 +392,9 @@ const LoadCellPackModelParams = {
         'file': PD.File({ accept: 'id' }),
     }, { options: [['id', 'Id'], ['file', 'File']] }),
     baseUrl: PD.Text(DefaultCellPackBaseUrl),
+    ingredients : PD.Group({
+        files: PD.FileList({ accept: '.cif,.pdb' })
+    }, { isExpanded: true }),
     preset: PD.Group({
         traceOnly: PD.Boolean(false),
         representation: PD.Select('gaussian-surface', PD.arrayToOptions(['spacefill', 'gaussian-surface', 'point', 'ellipsoid']))

+ 11 - 3
src/apps/viewer/extensions/cellpack/state.ts

@@ -9,6 +9,7 @@ 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';
 
 export const DefaultCellPackBaseUrl = 'https://mesoscope.scripps.edu/data/cellPACK_data/cellPACK_database_1.1.0/'
 
@@ -53,20 +54,27 @@ const StructureFromCellpack = PluginStateTransform.BuiltIn({
         if (!a) {
             return {
                 packing: PD.Numeric(0, {}, { description: 'Packing Index' }),
-                baseUrl: PD.Text(DefaultCellPackBaseUrl)
+                baseUrl: PD.Text(DefaultCellPackBaseUrl),
+                ingredientFiles: PD.FileList({ accept: '.cif,.pdb' })
             };
         }
         const options = a.data.packings.map((d, i) => [i, d.name] as [number, string])
         return {
             packing: PD.Select(0, options),
-            baseUrl: PD.Text(DefaultCellPackBaseUrl)
+            baseUrl: PD.Text(DefaultCellPackBaseUrl),
+            ingredientFiles: PD.FileList({ accept: '.cif,.pdb' })
         }
     }
 })({
     apply({ a, params }) {
         return Task.create('Structure from CellPack', async ctx => {
             const packing = a.data.packings[params.packing]
-            const structure = await createStructureFromCellPack(packing, params.baseUrl).runInContext(ctx)
+            const ingredientFiles: IngredientFiles = {}
+            for (let i = 0, il = params.ingredientFiles.length; i < il; ++i) {
+                const file = params.ingredientFiles.item(i)
+                if (file) ingredientFiles[file.name] = file
+            }
+            const structure = await createStructureFromCellPack(packing, params.baseUrl, ingredientFiles).runInContext(ctx)
             return new PSO.Molecule.Structure(structure, { label: packing.name })
         });
     }

+ 5 - 3
src/apps/viewer/extensions/cellpack/util.ts

@@ -7,14 +7,14 @@
 import { CIF } from '../../../../mol-io/reader/cif'
 import { parsePDB } from '../../../../mol-io/reader/pdb/parser';
 
-async function parseCif(data: string|Uint8Array) {
+export async function parseCif(data: string|Uint8Array) {
     const comp = CIF.parse(data);
     const parsed = await comp.run();
     if (parsed.isError) throw parsed;
     return parsed.result;
 }
 
-async function parsePDBfile(data: string, id: string) {
+export async function parsePDBfile(data: string, id: string) {
     const comp = parsePDB(data, id);
     const parsed = await comp.run();
     if (parsed.isError) throw parsed;
@@ -45,4 +45,6 @@ export async function getFromCellPackDB(id: string, baseUrl: string) {
     const name = id.endsWith('.pdb') ? id.substring(0, id.length - 4) : id
     const parsed = await downloadPDB(getCellPackDataUrl(id, baseUrl), name);
     return parsed;
-}
+}
+
+export type IngredientFiles = { [name: string]: File }