Browse Source

fix handling of mmcif with empty label_asym_id

Alexander Rose 3 years ago
parent
commit
18cc9790d1

+ 2 - 0
CHANGELOG.md

@@ -6,6 +6,8 @@ Note that since we don't clearly distinguish between a public and private interf
 
 ## [Unreleased]
 
+- Fix handling of mmcif with empty label_asym_id field
+
 ## [v3.3.1] - 2022-02-27
 
 - Fix issue with unit boundary reuse (do at visual level instead)

+ 9 - 2
src/mol-io/reader/cif/schema.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2017-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -53,11 +53,18 @@ function getColumnCtor(t: Column.Schema): ColumnCtor {
     }
 }
 
+function hasPresentValues(rowCount: number, valueKind: (row: number) => Column.ValueKind) {
+    for (let i = 0, il = rowCount; i < il; i++) {
+        if (valueKind(i) === Column.ValueKind.Present) return true;
+    }
+    return false;
+}
+
 function createColumn<T>(schema: Column.Schema, field: Data.CifField, value: (row: number) => T, toArray: Column<T>['toArray']): Column<T> {
     return {
         schema,
         __array: field.__array,
-        isDefined: field.isDefined,
+        isDefined: field.isDefined && hasPresentValues(field.rowCount, field.valueKind),
         rowCount: field.rowCount,
         value,
         valueKind: field.valueKind,

+ 6 - 9
src/mol-model-formats/structure/basic/atomic.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
@@ -29,10 +29,11 @@ function findHierarchyOffsets(atom_site: AtomSite) {
     const start = 0, end = atom_site._rowCount;
     const residues = [start as ElementIndex], chains = [start as ElementIndex];
 
-    const { label_entity_id, label_asym_id, label_seq_id, auth_seq_id, pdbx_PDB_ins_code } = atom_site;
+    const { label_entity_id, label_asym_id, auth_asym_id, label_seq_id, auth_seq_id, pdbx_PDB_ins_code } = atom_site;
+    const asym_id = label_asym_id.isDefined ? label_asym_id : auth_asym_id;
 
     for (let i = start + 1 as ElementIndex; i < end; i++) {
-        const newChain = !label_entity_id.areValuesEqual(i - 1, i) || !label_asym_id.areValuesEqual(i - 1, i);
+        const newChain = !label_entity_id.areValuesEqual(i - 1, i) || !asym_id.areValuesEqual(i - 1, i);
         const newResidue = newChain
             || !label_seq_id.areValuesEqual(i - 1, i)
             || !auth_seq_id.areValuesEqual(i - 1, i)
@@ -46,12 +47,8 @@ function findHierarchyOffsets(atom_site: AtomSite) {
 }
 
 function substUndefinedColumn<T extends Table<any>>(table: T, a: keyof T, b: keyof T) {
-    if (!(table as any)[a].isDefined) {
-        (table as any)[a] = (table as any)[b];
-    }
-    if (!(table as any)[b].isDefined) {
-        (table as any)[b] = (table as any)[a];
-    }
+    if (!table[a].isDefined) table[a] = table[b];
+    if (!table[b].isDefined) table[b] = table[a];
 }
 
 function createHierarchyData(atom_site: AtomSite, sourceIndex: Column<number>, offsets: { residues: ArrayLike<number>, chains: ArrayLike<number> }): AtomicData {

+ 4 - 3
src/mol-model-formats/structure/basic/sort.ts

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author David Sehnal <david.sehnal@gmail.com>
  */
@@ -18,11 +18,12 @@ export type SortedAtomSite = {
 export async function sortAtomSite(ctx: RuntimeContext, atom_site: AtomSite, start: number, end: number): Promise<SortedAtomSite> {
     const indices = createRangeArray(start, end - 1);
 
-    const { label_entity_id, label_asym_id, label_seq_id } = atom_site;
+    const { label_entity_id, label_asym_id, auth_asym_id, label_seq_id } = atom_site;
+    const asym_id = label_asym_id.isDefined ? label_asym_id : auth_asym_id;
     const entityBuckets = makeBuckets(indices, label_entity_id.value);
     if (ctx.shouldUpdate) await ctx.update();
     for (let ei = 0, _eI = entityBuckets.length - 1; ei < _eI; ei++) {
-        const chainBuckets = makeBuckets(indices, label_asym_id.value, { start: entityBuckets[ei], end: entityBuckets[ei + 1] });
+        const chainBuckets = makeBuckets(indices, asym_id.value, { start: entityBuckets[ei], end: entityBuckets[ei + 1] });
         for (let cI = 0, _cI = chainBuckets.length - 1; cI < _cI; cI++) {
             const aI = chainBuckets[cI];
             // are we in HETATM territory?