Browse Source

Merge branch 'master' of https://github.com/molstar/molstar into bond-dist-id

Alexander Rose 3 years ago
parent
commit
952b320975

+ 1 - 0
CHANGELOG.md

@@ -12,6 +12,7 @@ Note that since we don't clearly distinguish between a public and private interf
 - Improve bond assignment from ``IndexPairBonds``
     - Add ``id`` for mapping to source data
     - Fix assignment of bonds with unphysical length
+- Fix label/stats of single atom selection in multi-chain units
 
 ## [v3.0.0-dev.8] - 2021-12-31
 

+ 103 - 0
src/mol-io/reader/_spec/mol2.spec.ts

@@ -244,6 +244,84 @@ GASTEIGER
     25    13    23    1
     26    13    24    1`;
 
+const Mol2StringCrysin = `@<TRIPOS>MOLECULE
+1144204
+    12    11     2     0     0
+SMALL
+USER_CHARGES
+****
+Generated from the CSD
+
+@<TRIPOS>ATOM
+     1 Cl1      0.0925   3.6184   1.9845   Cl        1 RES1  -1.0000
+     2 C1      -4.7391   0.3350   0.4215   C.ar      2 RES2   0.0000
+     3 C2      -3.4121   0.2604   0.9351   C.ar      2 RES2   0.0000
+     4 C3      -2.9169   1.2555   1.7726   C.ar      2 RES2   0.0000
+     5 C4      -3.7118   2.3440   2.1099   C.ar      2 RES2   0.0000
+     6 C5      -5.0314   2.4052   1.6209   C.ar      2 RES2   0.0000
+     7 C6      -5.5372   1.4057   0.7962   C.ar      2 RES2   0.0000
+     8 C7      -6.9925   1.4547   0.3334   C.3       2 RES2   0.0000
+     9 C8      -7.8537   0.5554   1.1859   C.3       2 RES2   0.0000
+    10 N1      -9.3089   0.7134   0.8192   N.3       2 RES2   1.0000
+    11 O1      -2.6613  -0.8147   0.5707   O.3       2 RES2   0.0000
+    12 O2      -1.6204   1.0919   2.2584   O.3       2 RES2   0.0000
+@<TRIPOS>BOND
+     1     2     3   ar
+     2     3     4   ar
+     3     4     5   ar
+     4     5     6   ar
+     5     6     7   ar
+     6     7     2   ar
+     7     8     7    1
+     8     9     8    1
+     9    10     9    1
+    10    11     3    1
+    11    12     4    1
+@<TRIPOS>SUBSTRUCTURE
+     1 RES1        1 GROUP             0 ****  ****    0
+     2 RES2        2 GROUP             0 ****  ****    0
+@<TRIPOS>CRYSIN
+   10.5150   11.1300    7.9380   90.0000   90.0000   90.0000    29     5
+@<TRIPOS>MOLECULE
+   1144204
+    12    11     2     0     0
+SMALL
+USER_CHARGES
+****
+Generated from the CSD
+
+@<TRIPOS>ATOM
+     1 Cl1      0.0925   3.6184   1.9845   Cl        1 RES1  -1.0000
+     2 C1      -4.7391   0.3350   0.4215   C.ar      2 RES2   0.0000
+     3 C2      -3.4121   0.2604   0.9351   C.ar      2 RES2   0.0000
+     4 C3      -2.9169   1.2555   1.7726   C.ar      2 RES2   0.0000
+     5 C4      -3.7118   2.3440   2.1099   C.ar      2 RES2   0.0000
+     6 C5      -5.0314   2.4052   1.6209   C.ar      2 RES2   0.0000
+     7 C6      -5.5372   1.4057   0.7962   C.ar      2 RES2   0.0000
+     8 C7      -6.9925   1.4547   0.3334   C.3       2 RES2   0.0000
+     9 C8      -7.8537   0.5554   1.1859   C.3       2 RES2   0.0000
+    10 N1      -9.3089   0.7134   0.8192   N.3       2 RES2   1.0000
+    11 O1      -2.6613  -0.8147   0.5707   O.3       2 RES2   0.0000
+    12 O2      -1.6204   1.0919   2.2584   O.3       2 RES2   0.0000
+@<TRIPOS>BOND
+     1     2     3   ar
+     2     3     4   ar
+     3     4     5   ar
+     4     5     6   ar
+     5     6     7   ar
+     6     7     2   ar
+     7     8     7    1
+     8     9     8    1
+     9    10     9    1
+    10    11     3    1
+    11    12     4    1
+@<TRIPOS>SUBSTRUCTURE
+     1 RES1        1 GROUP             0 ****  ****    0
+     2 RES2        2 GROUP             0 ****  ****    0
+@<TRIPOS>CRYSIN
+   10.5150   11.1300    7.9380   90.0000   90.0000   90.0000    29     5
+`;
+
 describe('mol2 reader', () => {
     it('basic', async () => {
         const parsed = await parseMol2(Mol2String, '').run();
@@ -397,4 +475,29 @@ describe('mol2 reader', () => {
         // optional bond fields
         expect(bonds.status_bits.value(0)).toBe('');
     });
+
+    it('crysin', async () => {
+        const parsed = await parseMol2(Mol2StringCrysin, '').run();
+        if (parsed.isError) {
+            throw new Error(parsed.message);
+        }
+        const mol2File = parsed.result;
+
+        // number of structures
+        expect(mol2File.structures.length).toBe(2);
+
+        // crysin fields
+        for (const data of mol2File.structures) {
+            expect(data.crysin).toEqual({
+                a: 10.5150,
+                b: 11.1300,
+                c: 7.9380,
+                alpha: 90.0,
+                beta: 90.0,
+                gamma: 90.0,
+                spaceGroup: 29,
+                setting: 5
+            });
+        }
+    });
 });

+ 20 - 11
src/mol-io/reader/mol2/parser.ts

@@ -262,21 +262,30 @@ async function handleBonds(state: State): Promise<Schema.Mol2Bonds> {
 function handleCrysin(state: State) {
     const { tokenizer } = state;
 
-    while (getTokenString(tokenizer) !== '@<TRIPOS>CRYSIN' && tokenizer.position < tokenizer.data.length) {
-        markLine(tokenizer);
+    while (tokenizer.position < tokenizer.data.length) {
+        const l = getTokenString(tokenizer);
+        if (l === '@<TRIPOS>MOLECULE') {
+            return;
+        } else if (l === '@<TRIPOS>CRYSIN') {
+            break;
+        } else {
+            markLine(tokenizer);
+        }
     }
 
+    if (tokenizer.position >= tokenizer.data.length) return;
+
     markLine(tokenizer);
-    const l = getTokenString(tokenizer);
+    const values = getTokenString(tokenizer).trim().split(reWhitespace);
     return {
-        a: parseFloat(l.substring(0, 10)),
-        b: parseFloat(l.substring(10, 20)),
-        c: parseFloat(l.substring(20, 30)),
-        alpha: parseFloat(l.substring(30, 40)),
-        beta: parseFloat(l.substring(40, 50)),
-        gamma: parseFloat(l.substring(50, 60)),
-        spaceGroup: parseInt(l.substring(60, 70), 10),
-        setting: parseInt(l.substring(70, 80), 10),
+        a: parseFloat(values[0]),
+        b: parseFloat(values[1]),
+        c: parseFloat(values[2]),
+        alpha: parseFloat(values[3]),
+        beta: parseFloat(values[4]),
+        gamma: parseFloat(values[5]),
+        spaceGroup: parseInt(values[6], 10),
+        setting: parseInt(values[7], 10),
     };
 }
 

+ 1 - 1
src/mol-io/reader/mol2/schema.ts

@@ -72,7 +72,7 @@ export interface Mol2Structure {
     molecule: Readonly<Mol2Molecule>,
     atoms: Readonly<Mol2Atoms>,
     bonds: Readonly<Mol2Bonds>
-    crysin: Readonly<Mol2Crysin>
+    crysin?: Readonly<Mol2Crysin>
 }
 
 export interface Mol2File {

+ 4 - 2
src/mol-model-formats/structure/mol2.ts

@@ -114,8 +114,10 @@ async function getModels(mol2: Mol2File, ctx: RuntimeContext) {
                 type: molecule.charge_type
             });
 
-            const symmetry = getSymmetry(crysin);
-            if (symmetry) ModelSymmetry.Provider.set(first, symmetry);
+            if (crysin) {
+                const symmetry = getSymmetry(crysin);
+                if (symmetry) ModelSymmetry.Provider.set(first, symmetry);
+            }
 
             models.push(first);
         }

+ 7 - 0
src/mol-model/structure/structure/element/stats.ts

@@ -72,6 +72,7 @@ export namespace Stats {
             }
         } else if (size === 1) {
             if (Unit.Traits.is(unit.traits, Unit.Trait.MultiChain)) {
+                // handled in `handleUnitChainsSimple`
                 return;
             } else {
                 stats.elementCount += 1;
@@ -193,6 +194,12 @@ export namespace Stats {
                 if (stats.chainCount === 1) {
                     Location.set(stats.firstChainLoc, structure, unit, offsets[cI]);
                 }
+            } else if (size === 1) {
+                // need to handle here, skipped in `handleElement`
+                stats.elementCount += 1;
+                if (stats.elementCount === 1) {
+                    Location.set(stats.firstElementLoc, structure, unit, eI);
+                }
             }
         }
     }