From 60b5d2d39b6997beb39952e7a0a6af79657dde0d Mon Sep 17 00:00:00 2001
From: David Sehnal <dsehnal@users.noreply.github.com>
Date: Wed, 3 May 2023 15:37:24 +0200
Subject: [PATCH] fix labels & optimize getData (#811)

---
 .../sb-ncbr/partial-charges/labels.ts         |  3 +-
 .../sb-ncbr/partial-charges/property.ts       | 86 +++++++++++--------
 2 files changed, 53 insertions(+), 36 deletions(-)

diff --git a/src/extensions/sb-ncbr/partial-charges/labels.ts b/src/extensions/sb-ncbr/partial-charges/labels.ts
index 23c8fd742..d91a095e4 100644
--- a/src/extensions/sb-ncbr/partial-charges/labels.ts
+++ b/src/extensions/sb-ncbr/partial-charges/labels.ts
@@ -1,6 +1,6 @@
 import { StructureElement, StructureProperties } from '../../../mol-model/structure';
 import { LociLabel } from '../../../mol-plugin-state/manager/loci-label';
-import { SbNcbrPartialChargesPropertyProvider } from './property';
+import { SbNcbrPartialChargesPropertyProvider, hasPartialChargesCategories } from './property';
 import { Loci } from '../../../mol-model/loci';
 import { PluginContext } from '../../../mol-plugin/context';
 import { LociLabelProvider } from '../../../mol-plugin-state/manager/loci-label';
@@ -11,6 +11,7 @@ export function SbNcbrPartialChargesLociLabelProvider(ctx: PluginContext): LociL
             if (!StructureElement.Loci.is(loci)) return;
 
             const model = loci.structure.model;
+            if (!hasPartialChargesCategories(model)) return;
             const data = SbNcbrPartialChargesPropertyProvider.get(model).value;
             if (!data) return;
 
diff --git a/src/extensions/sb-ncbr/partial-charges/property.ts b/src/extensions/sb-ncbr/partial-charges/property.ts
index b4cecba86..7cb37f64c 100644
--- a/src/extensions/sb-ncbr/partial-charges/property.ts
+++ b/src/extensions/sb-ncbr/partial-charges/property.ts
@@ -15,44 +15,60 @@ export interface SBNcbrPartialChargeData {
     maxAbsoluteAtomCharges: IdToCharge;
     maxAbsoluteResidueCharges: IdToCharge;
     maxAbsoluteAtomChargeAll: number;
+    params: PartialChargesPropertyParams;
 }
 
 const PartialChargesPropertyParams = {
     typeId: PD.Select<number>(0, [[0, '0']]),
 };
 type PartialChargesPropertyParams = typeof PartialChargesPropertyParams;
-const defaultPartialChargesPropertyParams = PD.clone(PartialChargesPropertyParams);
+const DefaultPartialChargesPropertyParams = PD.clone(PartialChargesPropertyParams);
 
 function getParams(model: Model) {
-    const typeIdToMethod = getTypeIdToMethod(model);
-    const options = Array.from(typeIdToMethod.entries()).map(
-        ([typeId, method]) => [typeId, method] as [number, string]
-    );
-    return {
-        typeId: PD.Select<number>(1, options),
-    };
+    return getData(model).value?.params ?? DefaultPartialChargesPropertyParams;
 }
 
-async function getData(model: Model): Promise<CustomProperty.Data<SBNcbrPartialChargeData | undefined>> {
-    if (!SbNcbrPartialChargesPropertyProvider.isApplicable(model)) return { value: undefined };
-
-    const typeIdToMethod = getTypeIdToMethod(model);
-    const typeIdToAtomIdToCharge = getTypeIdToAtomIdToCharge(model);
-    const typeIdToResidueToCharge = getTypeIdToResidueIdToCharge(model, typeIdToAtomIdToCharge);
-    const maxAbsoluteAtomCharges = getMaxAbsoluteCharges(typeIdToAtomIdToCharge);
-    const maxAbsoluteResidueCharges = getMaxAbsoluteCharges(typeIdToResidueToCharge);
-    const maxAbsoluteAtomChargeAll = getMaxAbsoluteAtomChargeAll(maxAbsoluteAtomCharges, maxAbsoluteResidueCharges);
-
-    return {
-        value: {
-            typeIdToMethod,
-            typeIdToAtomIdToCharge,
-            typeIdToResidueToCharge,
-            maxAbsoluteAtomCharges,
-            maxAbsoluteResidueCharges,
-            maxAbsoluteAtomChargeAll,
-        },
-    };
+const PropertyKey = 'sb-ncbr-partial-charges-property-data';
+
+function getData(model: Model): CustomProperty.Data<SBNcbrPartialChargeData | undefined> {
+    if (PropertyKey in model._staticPropertyData) {
+        return model._staticPropertyData[PropertyKey];
+    }
+
+    let data: CustomProperty.Data<SBNcbrPartialChargeData | undefined>;
+
+    if (!SbNcbrPartialChargesPropertyProvider.isApplicable(model)) {
+        data = { value: undefined };
+    } else {
+        const typeIdToMethod = getTypeIdToMethod(model);
+        const typeIdToAtomIdToCharge = getTypeIdToAtomIdToCharge(model);
+        const typeIdToResidueToCharge = getTypeIdToResidueIdToCharge(model, typeIdToAtomIdToCharge);
+        const maxAbsoluteAtomCharges = getMaxAbsoluteCharges(typeIdToAtomIdToCharge);
+        const maxAbsoluteResidueCharges = getMaxAbsoluteCharges(typeIdToResidueToCharge);
+        const maxAbsoluteAtomChargeAll = getMaxAbsoluteAtomChargeAll(maxAbsoluteAtomCharges, maxAbsoluteResidueCharges);
+
+        const options = Array.from(typeIdToMethod.entries()).map(
+            ([typeId, method]) => [typeId, method] as [number, string]
+        );
+        const params = {
+            typeId: PD.Select<number>(1, options),
+        };
+
+        data = {
+            value: {
+                typeIdToMethod,
+                typeIdToAtomIdToCharge,
+                typeIdToResidueToCharge,
+                maxAbsoluteAtomCharges,
+                maxAbsoluteResidueCharges,
+                maxAbsoluteAtomChargeAll,
+                params,
+            },
+        };
+    }
+
+    model._staticPropertyData[PropertyKey] = data;
+    return data;
 }
 
 function getTypeIdToMethod(model: Model) {
@@ -164,11 +180,11 @@ function getMaxAbsoluteAtomChargeAll(
 
 export function hasPartialChargesCategories(model: Model): boolean {
     if (!model || !MmcifFormat.is(model.sourceData)) return false;
-    const names = model.sourceData.data.frame.categoryNames;
+    const { categories } = model.sourceData.data.frame;
     return (
-        names.includes('atom_site') &&
-        names.includes('sb_ncbr_partial_atomic_charges') &&
-        names.includes('sb_ncbr_partial_atomic_charges_meta')
+        'atom_site' in categories &&
+        'sb_ncbr_partial_atomic_charges' in categories &&
+        'sb_ncbr_partial_atomic_charges_meta' in categories
     );
 }
 
@@ -178,11 +194,11 @@ SBNcbrPartialChargeData | undefined
 > = CustomModelProperty.createProvider({
     label: 'SB NCBR Partial Charges Property Provider',
     descriptor: CustomPropertyDescriptor({
-        name: 'sb-ncbr-property-provider',
+        name: 'sb-ncbr-partial-charges-property-provider',
     }),
     type: 'static',
-    defaultParams: defaultPartialChargesPropertyParams,
+    defaultParams: DefaultPartialChargesPropertyParams,
     getParams: (data: Model) => getParams(data),
     isApplicable: (model: Model) => hasPartialChargesCategories(model),
-    obtain: (_ctx: CustomProperty.Context, model: Model) => getData(model),
+    obtain: (_ctx: CustomProperty.Context, model: Model) => Promise.resolve(getData(model)),
 });
-- 
GitLab