Bladeren bron

cellpack: simple cache to avoid parsing trajectories more than once

Alexander Rose 5 jaren geleden
bovenliggende
commit
690d6812dc
1 gewijzigde bestanden met toevoegingen van 54 en 44 verwijderingen
  1. 54 44
      src/extensions/cellpack/model.ts

+ 54 - 44
src/extensions/cellpack/model.ts

@@ -34,56 +34,66 @@ function getCellPackModelUrl(fileName: string, baseUrl: string) {
     return `${baseUrl}/results/${fileName}`;
 }
 
-async function getModel(plugin: PluginContext, id: string, ingredient: Ingredient, baseUrl: string, file?: Asset.File) {
+class TrajectoryCache {
+    private map = new Map<string, Model.Trajectory>();
+    set(id: string, trajectory: Model.Trajectory) { this.map.set(id, trajectory); }
+    get(id: string) { return this.map.get(id); }
+}
+
+async function getModel(plugin: PluginContext, id: string, ingredient: Ingredient, baseUrl: string, trajCache: TrajectoryCache, file?: Asset.File) {
     const assetManager = plugin.managers.asset;
-    const model_id = (ingredient.source.model) ? parseInt(ingredient.source.model) : 0;
+    const modelIndex = (ingredient.source.model) ? parseInt(ingredient.source.model) : 0;
     const surface = (ingredient.ingtype) ? (ingredient.ingtype === 'transmembrane') : false;
-    let model: Model;
+    let trajectory = trajCache.get(id);
     let assets: Asset.Wrapper[] = [];
-    if (file) {
-        if (file.name.endsWith('.cif')) {
-            const text = await plugin.runTask(assetManager.resolve(file, 'string'));
-            assets.push(text);
-            const cif = (await parseCif(plugin, text.data)).blocks[0];
-            model = (await plugin.runTask(trajectoryFromMmCIF(cif)))[model_id];
-        } else if (file.name.endsWith('.bcif')) {
-            const binary = await plugin.runTask(assetManager.resolve(file, 'binary'));
-            assets.push(binary);
-            const cif = (await parseCif(plugin, binary.data)).blocks[0];
-            model = (await plugin.runTask(trajectoryFromMmCIF(cif)))[model_id];
-        } else if (file.name.endsWith('.pdb')) {
-            const text = await plugin.runTask(assetManager.resolve(file, 'string'));
-            assets.push(text);
-            const pdb = await parsePDBfile(plugin, text.data, id);
-            model = (await plugin.runTask(trajectoryFromPDB(pdb)))[model_id];
-        } else {
-            throw new Error(`unsupported file type '${file.name}'`);
-        }
-    } else if (id.match(/^[1-9][a-zA-Z0-9]{3,3}$/i)) {
-        if (surface){
-            const data = await getFromOPM(plugin, id, assetManager);
-            if (data.asset){
-                assets.push(data.asset);
-                model = (await plugin.runTask(trajectoryFromPDB(data.pdb)))[model_id];
+    if (!trajectory) {
+        if (file) {
+            if (file.name.endsWith('.cif')) {
+                const text = await plugin.runTask(assetManager.resolve(file, 'string'));
+                assets.push(text);
+                const cif = (await parseCif(plugin, text.data)).blocks[0];
+                trajectory = await plugin.runTask(trajectoryFromMmCIF(cif));
+            } else if (file.name.endsWith('.bcif')) {
+                const binary = await plugin.runTask(assetManager.resolve(file, 'binary'));
+                assets.push(binary);
+                const cif = (await parseCif(plugin, binary.data)).blocks[0];
+                trajectory = await plugin.runTask(trajectoryFromMmCIF(cif));
+            } else if (file.name.endsWith('.pdb')) {
+                const text = await plugin.runTask(assetManager.resolve(file, 'string'));
+                assets.push(text);
+                const pdb = await parsePDBfile(plugin, text.data, id);
+                trajectory = await plugin.runTask(trajectoryFromPDB(pdb));
+            } else {
+                throw new Error(`unsupported file type '${file.name}'`);
+            }
+        } else if (id.match(/^[1-9][a-zA-Z0-9]{3,3}$/i)) {
+            if (surface){
+                const data = await getFromOPM(plugin, id, assetManager);
+                if (data.asset){
+                    assets.push(data.asset);
+                    trajectory = await plugin.runTask(trajectoryFromPDB(data.pdb));
+                } else {
+                    const { mmcif, asset } = await getFromPdb(plugin, id, assetManager);
+                    assets.push(asset);
+                    trajectory = await plugin.runTask(trajectoryFromMmCIF(mmcif));
+                }
             } else {
                 const { mmcif, asset } = await getFromPdb(plugin, id, assetManager);
                 assets.push(asset);
-                model = (await plugin.runTask(trajectoryFromMmCIF(mmcif)))[model_id];
+                trajectory = await plugin.runTask(trajectoryFromMmCIF(mmcif));
             }
         } else {
-            const { mmcif, asset } = await getFromPdb(plugin, id, assetManager);
-            assets.push(asset);
-            model = (await plugin.runTask(trajectoryFromMmCIF(mmcif)))[model_id];
-        }
-    } else {
-        const data = await getFromCellPackDB(plugin, id, baseUrl, assetManager);
-        assets.push(data.asset);
-        if ('pdb' in data) {
-            model = (await plugin.runTask(trajectoryFromPDB(data.pdb)))[model_id];
-        } else {
-            model = (await plugin.runTask(trajectoryFromMmCIF(data.mmcif)))[model_id];
+            const data = await getFromCellPackDB(plugin, id, baseUrl, assetManager);
+            assets.push(data.asset);
+            if ('pdb' in data) {
+                trajectory = await plugin.runTask(trajectoryFromPDB(data.pdb));
+            } else {
+                trajectory = await plugin.runTask(trajectoryFromMmCIF(data.mmcif));
+            }
         }
+        trajCache.set(id, trajectory);
     }
+    const model = trajectory[modelIndex];
     return { model, assets };
 }
 
@@ -135,7 +145,6 @@ function getTransform(trans: Vec3, rot: Quat) {
     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]));
@@ -290,7 +299,7 @@ async function getCurve(plugin: PluginContext, name: string, ingredient: Ingredi
     return getStructure(plugin, curveModel, ingredient.source);
 }
 
-async function getIngredientStructure(plugin: PluginContext, ingredient: Ingredient, baseUrl: string, ingredientFiles: IngredientFiles) {
+async function getIngredientStructure(plugin: PluginContext, ingredient: Ingredient, baseUrl: string, ingredientFiles: IngredientFiles, trajCache: TrajectoryCache) {
     const { name, source, results, nbCurve } = ingredient;
     if (source.pdb === 'None') return;
 
@@ -305,7 +314,7 @@ async function getIngredientStructure(plugin: PluginContext, ingredient: Ingredi
     }
 
     // model id in case structure is NMR
-    const { model, assets } = await getModel(plugin, source.pdb || name, ingredient, baseUrl, file);
+    const { model, assets } = await getModel(plugin, source.pdb || name, ingredient, baseUrl, trajCache, file);
     if (!model) return;
 
     let structure: Structure;
@@ -356,10 +365,11 @@ export function createStructureFromCellPack(plugin: PluginContext, packing: Cell
     return Task.create('Create Packing Structure', async ctx => {
         const { ingredients, name } = packing;
         const assets: Asset.Wrapper[] = [];
+        const trajCache = new TrajectoryCache();
         const structures: Structure[] = [];
         for (const iName in ingredients) {
             if (ctx.shouldUpdate) await ctx.update(iName);
-            const ingredientStructure = await getIngredientStructure(plugin, ingredients[iName], baseUrl, ingredientFiles);
+            const ingredientStructure = await getIngredientStructure(plugin, ingredients[iName], baseUrl, ingredientFiles, trajCache);
             if (ingredientStructure) {
                 structures.push(ingredientStructure.structure);
                 assets.push(...ingredientStructure.assets);