Browse Source

FTR: Add formal charges during model creation

This implementation takes into account both the property and atom block
cases and makes sure the latter is ignored if the first one is present.
ptourlas 3 years ago
parent
commit
cb76b53a1b
2 changed files with 69 additions and 7 deletions
  1. 39 4
      src/mol-io/reader/mol/parser.ts
  2. 30 3
      src/mol-model-formats/structure/mol.ts

+ 39 - 4
src/mol-io/reader/mol/parser.ts

@@ -63,6 +63,45 @@ export interface MolFile {
     nnn         (INVERSION/RETENTION FLAG, 63-66)
     eee         (EXACT CHANGE FLAG, 66-69)
 */
+
+/**
+ * @param key - The value found at the atom block.
+ * @returns The actual formal charge based on the mapping.
+ */
+export function formalChargeMapper(key: string) {
+    let chg = 0;
+    switch (key) {
+        case '7':
+            chg = -3;
+            break;
+        case '6':
+            chg = -2;
+            break;
+        case '5':
+            chg = -1;
+            break;
+        case '0':
+            chg = 0;
+            break;
+        case '3':
+            chg = 1;
+            break;
+        case '2':
+            chg = 2;
+            break;
+        case '1':
+            chg = 3;
+            break;
+        case '4':
+            chg = 0;
+            break;
+        default:
+            console.error(`Value to be mapped is outside the 0-7 range!`);
+            break;
+    }
+    return chg;
+}
+
 export function handleAtoms(tokenizer: Tokenizer, count: number): MolFile['atoms'] {
     const x = TokenBuilder.create(tokenizer.data, count * 2);
     const y = TokenBuilder.create(tokenizer.data, count * 2);
@@ -147,12 +186,8 @@ export function handleFormalCharges(tokenizer: Tokenizer, lineStart: number): Mo
 
         Tokenizer.trim(tokenizer, lineStart + offset, lineStart + offset + 4);
         TokenBuilder.addUnchecked(atomIdx, tokenizer.tokenStart, tokenizer.tokenEnd);
-        console.log('id', Tokenizer.getTokenString(tokenizer));
-
         Tokenizer.trim(tokenizer, lineStart + offset + 4, lineStart + offset + 8);
         TokenBuilder.addUnchecked(charge, tokenizer.tokenStart, tokenizer.tokenEnd);
-        console.log('chg', Tokenizer.getTokenString(tokenizer));
-
     }
 
     /*

+ 30 - 3
src/mol-model-formats/structure/mol.ts

@@ -7,7 +7,7 @@
  */
 
 import { Column, Table } from '../../mol-data/db';
-import { MolFile } from '../../mol-io/reader/mol/parser';
+import { MolFile, formalChargeMapper } from '../../mol-io/reader/mol/parser';
 import { MoleculeType } from '../../mol-model/structure/model/types';
 import { RuntimeContext, Task } from '../../mol-task';
 import { createModels } from './basic/parser';
@@ -19,13 +19,40 @@ import { IndexPairBonds } from './property/bonds/index-pair';
 import { Trajectory } from '../../mol-model/structure';
 
 export async function getMolModels(mol: MolFile, format: ModelFormat<any> | undefined, ctx: RuntimeContext) {
-    const { atoms, bonds } = mol;
+    const { atoms, bonds, formalCharges } = mol;
 
     const MOL = Column.ofConst('MOL', mol.atoms.count, Column.Schema.str);
     const A = Column.ofConst('A', mol.atoms.count, Column.Schema.str);
     const type_symbol = Column.asArrayColumn(atoms.type_symbol);
     const seq_id = Column.ofConst(1, atoms.count, Column.Schema.int);
 
+    const computedFormalCharges: Column<number> = Column.ofLambda({
+        value: (row: number) => {
+            if (formalCharges) {
+                const numOfCharges = formalCharges.atomIdx.rowCount;
+                /*
+                    Scan the list of formal charges from the properties
+                    block. If one of them has an atom index that matches the
+                    current row return the corresponding charge.
+                */
+                for (let i = 0; i < numOfCharges; i++) {
+                    if ((formalCharges.atomIdx.value(i) - 1) === row) {
+                        return formalCharges.charge.value(i);
+                    }
+                }
+                /*
+                    If the M CHG property is present, every charge in the atom
+                    block is treated as zero.
+                */
+                return 0;
+            }
+            const idx = atoms.formal_charge.value(row).toString();
+            return formalChargeMapper(idx);
+        },
+        rowCount: atoms.formal_charge.rowCount,
+        schema: atoms.formal_charge.schema,
+    });
+
     const atom_site = Table.ofPartialColumns(BasicSchema.atom_site, {
         auth_asym_id: A,
         auth_atom_id: type_symbol,
@@ -46,7 +73,7 @@ export async function getMolModels(mol: MolFile, format: ModelFormat<any> | unde
         type_symbol,
 
         pdbx_PDB_model_num: Column.ofConst(1, atoms.count, Column.Schema.int),
-        pdbx_formal_charge: Column.asArrayColumn(atoms.formal_charge)
+        pdbx_formal_charge: computedFormalCharges
     }, atoms.count);
 
     const entityBuilder = new EntityBuilder();