Ver Fonte

add xyz support

dsehnal há 4 anos atrás
pai
commit
29d4cfbcca

+ 71 - 0
src/mol-io/reader/xyz/parser.ts

@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Column } from '../../../mol-data/db';
+import { Task } from '../../../mol-task';
+import { Tokenizer } from '../common/text/tokenizer';
+import { ReaderResult as Result } from '../result';
+
+export interface XyzFile {
+    readonly molecules: {
+        readonly comment: string,
+        readonly count: number,
+        readonly x: Column<number>,
+        readonly y: Column<number>,
+        readonly z: Column<number>,
+        readonly type_symbol: Column<string>
+    }[],
+}
+
+function handleMolecule(tokenizer: Tokenizer): XyzFile['molecules'][number] {
+    let count = tokenizer.position >= tokenizer.data.length - 1 ? 0 : +Tokenizer.readLine(tokenizer);
+    if (isNaN(count)) count = 0;
+
+    const comment = Tokenizer.readLine(tokenizer);
+
+    const x = new Float64Array(count);
+    const y = new Float64Array(count);
+    const z = new Float64Array(count);
+    const type_symbol = new Array<string>(count);
+
+    for (let i = 0; i < count; ++i) {
+        const line = Tokenizer.readLine(tokenizer);
+        const fields = line.split(/\s+/g);
+        type_symbol[i] = fields[0];
+        x[i] = +fields[1];
+        y[i] = +fields[2];
+        z[i] = +fields[3];
+    }
+
+    return {
+        count,
+        comment,
+        x: Column.ofFloatArray(x),
+        y: Column.ofFloatArray(y),
+        z: Column.ofFloatArray(z),
+        type_symbol: Column.ofStringArray(type_symbol)
+    };
+}
+
+function parseInternal(data: string): Result<XyzFile> {
+    const tokenizer = Tokenizer(data);
+
+    const molecules: XyzFile['molecules'] = [];
+    while (true) {
+        const mol = handleMolecule(tokenizer);
+        if (mol.count === 0) break;
+        molecules.push(mol);
+    }
+
+    const result: XyzFile = { molecules };
+    return Result.success(result);
+}
+
+export function parseXyz(data: string) {
+    return Task.create<Result<XyzFile>>('Parse Mol', async () => {
+        return parseInternal(data);
+    });
+}

+ 108 - 0
src/mol-model-formats/structure/xyz.ts

@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Column, Table } from '../../mol-data/db';
+import { XyzFile } from '../../mol-io/reader/xyz/parser';
+import { Trajectory } from '../../mol-model/structure';
+import { MoleculeType } from '../../mol-model/structure/model/types';
+import { RuntimeContext, Task } from '../../mol-task';
+import { ModelFormat } from '../format';
+import { createModels } from './basic/parser';
+import { BasicSchema, createBasic } from './basic/schema';
+import { ComponentBuilder } from './common/component';
+import { EntityBuilder } from './common/entity';
+
+function getModels(mol: XyzFile, ctx: RuntimeContext) {
+    const { molecules } = mol;
+
+    let count = 0;
+    for (const m of molecules) count += m.count;
+
+    const type_symbols = new Array<string>(count);
+    const id = new Int32Array(count);
+    const x = new Float32Array(count);
+    const y = new Float32Array(count);
+    const z = new Float32Array(count);
+    const model_num = new Int32Array(count);
+
+    let offset = 0;
+    for (let i = 0; i < molecules.length; i++) {
+        const m = molecules[i];
+        for (let j = 0; j < m.count; j++) {
+            type_symbols[offset] = m.type_symbol.value(j);
+            x[offset] = m.x.value(j);
+            y[offset] = m.y.value(j);
+            z[offset] = m.z.value(j);
+            id[offset] = j;
+            model_num[offset] = i;
+            offset++;
+        }
+    }
+
+    const MOL = Column.ofConst('MOL', count, Column.Schema.str);
+    const A = Column.ofConst('A', count, Column.Schema.str);
+    const seq_id = Column.ofConst(1, count, Column.Schema.int);
+
+    const type_symbol = Column.ofStringArray(type_symbols);
+
+    const atom_site = Table.ofPartialColumns(BasicSchema.atom_site, {
+        auth_asym_id: A,
+        auth_atom_id: type_symbol,
+        auth_comp_id: MOL,
+        auth_seq_id: seq_id,
+        Cartn_x: Column.ofFloatArray(x),
+        Cartn_y: Column.ofFloatArray(y),
+        Cartn_z: Column.ofFloatArray(z),
+        id: Column.ofIntArray(id),
+
+        label_asym_id: A,
+        label_atom_id: type_symbol,
+        label_comp_id: MOL,
+        label_seq_id: seq_id,
+        label_entity_id: Column.ofConst('1', count, Column.Schema.str),
+
+        occupancy: Column.ofConst(1, count, Column.Schema.float),
+        type_symbol,
+
+        pdbx_PDB_model_num: Column.ofIntArray(model_num),
+    }, count);
+
+    const entityBuilder = new EntityBuilder();
+    entityBuilder.setNames([['MOL', 'Unknown Entity']]);
+    entityBuilder.getEntityId('MOL', MoleculeType.Unknown, 'A');
+
+    const componentBuilder = new ComponentBuilder(seq_id, type_symbol);
+    componentBuilder.setNames([['MOL', 'Unknown Molecule']]);
+    componentBuilder.add('MOL', 0);
+
+    const basics = createBasic({
+        entity: entityBuilder.getEntityTable(),
+        chem_comp: componentBuilder.getChemCompTable(),
+        atom_site
+    });
+
+    return createModels(basics, MolFormat.create(mol), ctx);
+}
+
+//
+
+export { XyzFormat };
+
+type XyzFormat = ModelFormat<XyzFile>
+
+namespace MolFormat {
+    export function is(x?: ModelFormat): x is XyzFormat {
+        return x?.kind === 'mol';
+    }
+
+    export function create(mol: XyzFile): XyzFormat {
+        return { kind: 'xyz', name: 'xyz', data: mol };
+    }
+}
+
+export function trajectoryFromXyz(mol: XyzFile): Task<Trajectory> {
+    return Task.create('Parse XYZ', ctx => getModels(mol, ctx));
+}

+ 10 - 0
src/mol-plugin-state/formats/trajectory.ts

@@ -103,6 +103,15 @@ export const PdbqtProvider: TrajectoryFormatProvider = {
     visuals: defaultVisuals
 };
 
+export const XyzProvider: TrajectoryFormatProvider = {
+    label: 'XYZ',
+    description: 'XYZ',
+    category: TrajectoryFormatCategory,
+    stringExtensions: ['xyz'],
+    parse: directTrajectory(StateTransforms.Model.TrajectoryFromXYZ),
+    visuals: defaultVisuals
+};
+
 export const GroProvider: TrajectoryFormatProvider = {
     label: 'GRO',
     description: 'GRO',
@@ -137,6 +146,7 @@ export const BuiltInTrajectoryFormats = [
     ['pdb', PdbProvider] as const,
     ['pdbqt', PdbqtProvider] as const,
     ['gro', GroProvider] as const,
+    ['xyz', XyzProvider] as const,
     ['mol', MolProvider] as const,
     ['mol2', Mol2Provider] as const,
 ] as const;

+ 21 - 0
src/mol-plugin-state/transforms/model.ts

@@ -37,6 +37,8 @@ import { parseMol2 } from '../../mol-io/reader/mol2/parser';
 import { trajectoryFromMol2 } from '../../mol-model-formats/structure/mol2';
 import { parseXtc } from '../../mol-io/reader/xtc/parser';
 import { coordinatesFromXtc } from '../../mol-model-formats/structure/xtc';
+import { parseXyz } from '../../mol-io/reader/xyz/parser';
+import { trajectoryFromXyz } from '../../mol-model-formats/structure/xyz';
 
 export { CoordinatesFromDcd };
 export { CoordinatesFromXtc };
@@ -46,6 +48,7 @@ export { TrajectoryFromBlob };
 export { TrajectoryFromMmCif };
 export { TrajectoryFromPDB };
 export { TrajectoryFromGRO };
+export { TrajectoryFromXYZ };
 export { TrajectoryFromMOL };
 export { TrajectoryFromMOL2 };
 export { TrajectoryFromCube };
@@ -253,6 +256,24 @@ const TrajectoryFromGRO = PluginStateTransform.BuiltIn({
     }
 });
 
+type TrajectoryFromXYZ = typeof TrajectoryFromXYZ
+const TrajectoryFromXYZ = PluginStateTransform.BuiltIn({
+    name: 'trajectory-from-xyz',
+    display: { name: 'Parse XYZ', description: 'Parse XYZ string and create trajectory.' },
+    from: [SO.Data.String],
+    to: SO.Molecule.Trajectory
+})({
+    apply({ a }) {
+        return Task.create('Parse XYZ', async ctx => {
+            const parsed = await parseXyz(a.data).runInContext(ctx);
+            if (parsed.isError) throw new Error(parsed.message);
+            const models = await trajectoryFromXyz(parsed.result).runInContext(ctx);
+            const props = trajectoryProps(models);
+            return new SO.Molecule.Trajectory(models, props);
+        });
+    }
+});
+
 type TrajectoryFromMOL = typeof TrajectoryFromMOL
 const TrajectoryFromMOL = PluginStateTransform.BuiltIn({
     name: 'trajectory-from-mol',