Skip to content
Snippets Groups Projects
Commit 901fac97 authored by Alexander Rose's avatar Alexander Rose
Browse files

basic support for .3dg files

parent 29b6a883
Branches
Tags
No related merge requests found
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ReaderResult as Result } from '../result'
import { Task } from '../../../mol-task'
import { parseCsv } from '../csv/parser';
import { Column, Table } from '../../../mol-data/db';
import { toTable } from '../cif/schema';
import Schema = Column.Schema
import { CsvTable } from '../csv/data-model';
export const Schema3DG = {
/** Chromosome name */
chromosome: Schema.str,
/** Base position */
position: Schema.int,
/** X coordinate */
x: Schema.float,
/** Y coordinate */
y: Schema.float,
/** Z coordinate */
z: Schema.float,
}
export type Schema3DG = typeof Schema3DG
export interface File3DG {
table: Table<Schema3DG>
}
const FieldNames = [ 'chromosome', 'position', 'x', 'y', 'z' ]
function categoryFromTable(name: string, table: CsvTable) {
return {
name,
rowCount: table.rowCount,
fieldNames: FieldNames,
getField: (name: string) => {
return table.getColumn(FieldNames.indexOf(name).toString())
}
}
}
export function parse3DG(data: string) {
return Task.create<Result<File3DG>>('Parse 3DG', async ctx => {
const opts = { quote: '', comment: '#', delimiter: '\t', noColumnNames: true }
const csvFile = await parseCsv(data, opts).runInContext(ctx)
if (csvFile.isError) return Result.error(csvFile.message, csvFile.line)
const category = categoryFromTable('3dg', csvFile.result.table)
const table = toTable(Schema3DG, category)
return Result.success({ table })
});
}
\ No newline at end of file
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { parse3DG } from '../3dg/parser';
const basic3dgString = `1(mat) 1420000 0.791377837067 10.9947291355 -13.1882897693
1(mat) 1440000 -0.268241283699 10.5200875887 -13.0896257278
1(mat) 1460000 -1.3853075236 10.5513787498 -13.1440142173
1(mat) 1480000 -1.55984101733 11.4340829129 -13.6026301209
1(mat) 1500000 -0.770991778399 11.4758488546 -14.5881137222
1(mat) 1520000 -0.0848245107875 12.2624690808 -14.354289628
1(mat) 1540000 -0.458643807046 12.5985791771 -13.4701149287
1(mat) 1560000 -0.810322906201 12.2461643989 -12.3172933413
1(mat) 1580000 -2.08211172035 12.8886838656 -12.8742007778
1(mat) 1600000 -3.52093948201 13.1850935438 -12.4118684428`
describe('3dg reader', () => {
it('basic', async () => {
const parsed = await parse3DG(basic3dgString).run();
expect(parsed.isError).toBe(false)
if (parsed.isError) return;
const { chromosome, position, x, y, z } = parsed.result.table;
expect(chromosome.value(0)).toBe('1(mat)')
expect(position.value(1)).toBe(1440000)
expect(x.value(5)).toBe(-0.0848245107875)
expect(y.value(5)).toBe(12.2624690808)
expect(z.value(5)).toBe(-14.354289628)
});
});
\ No newline at end of file
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { Model } from '../../mol-model/structure/model';
import { Task } from '../../mol-task';
import { ModelFormat } from './format';
import { _parse_mmCif } from './mmcif/parser';
import { CifCategory, CifField } from '../../mol-io/reader/cif';
import { Column } from '../../mol-data/db';
import { mmCIF_Schema } from '../../mol-io/reader/cif/schema/mmcif';
import { EntityBuilder } from './common/entity';
import { File3DG } from '../../mol-io/reader/3dg/parser';
import { fillSerial } from '../../mol-util/array';
import { MoleculeType } from '../../mol-model/structure/model/types';
function getCategories(table: File3DG['table']) {
const entityIds = new Array<string>(table._rowCount)
const entityBuilder = new EntityBuilder()
const seqIdStarts = table.position.toArray({ array: Uint32Array })
const seqIdEnds = new Uint32Array(table._rowCount)
const stride = seqIdStarts[1] - seqIdStarts[0]
const objectRadius = stride / 3500
for (let i = 0, il = table._rowCount; i < il; ++i) {
const chr = table.chromosome.value(i)
const entityId = entityBuilder.getEntityId(chr, MoleculeType.DNA, chr)
entityIds[i] = entityId
seqIdEnds[i] = seqIdStarts[i] + stride - 1
}
const ihm_sphere_obj_site: CifCategory.SomeFields<mmCIF_Schema['ihm_sphere_obj_site']> = {
id: CifField.ofNumbers(fillSerial(new Uint32Array(table._rowCount))),
entity_id: CifField.ofStrings(entityIds),
seq_id_begin: CifField.ofNumbers(seqIdStarts),
seq_id_end: CifField.ofNumbers(seqIdEnds),
asym_id: CifField.ofColumn(table.chromosome),
Cartn_x: CifField.ofNumbers(Column.mapToArray(table.x, x => x * 10, Float32Array)),
Cartn_y: CifField.ofNumbers(Column.mapToArray(table.y, y => y * 10, Float32Array)),
Cartn_z: CifField.ofNumbers(Column.mapToArray(table.z, z => z * 10, Float32Array)),
object_radius: CifField.ofColumn(Column.ofConst(objectRadius, table._rowCount, Column.Schema.float)),
rmsf: CifField.ofColumn(Column.ofConst(0, table._rowCount, Column.Schema.float)),
model_id: CifField.ofColumn(Column.ofConst(1, table._rowCount, Column.Schema.int)),
}
return {
entity: entityBuilder.getEntityCategory(),
ihm_model_list: CifCategory.ofFields('ihm_model_list', {
model_id: CifField.ofNumbers([1]),
model_name: CifField.ofStrings(['3DG Model']),
}),
ihm_sphere_obj_site: CifCategory.ofFields('ihm_sphere_obj_site', ihm_sphere_obj_site)
}
}
async function mmCifFrom3dg(file3dg: File3DG) {
const categories = getCategories(file3dg.table)
return {
header: '3DG',
categoryNames: Object.keys(categories),
categories
};
}
export function trajectoryFrom3DG(file3dg: File3DG): Task<Model.Trajectory> {
return Task.create('Parse 3DG', async ctx => {
await ctx.update('Converting to mmCIF');
const cif = await mmCifFrom3dg(file3dg);
const format = ModelFormat.mmCIF(cif);
return _parse_mmCif(format, ctx);
})
}
......@@ -12,7 +12,7 @@ import { PluginStateObject } from '../objects';
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
import { Ccp4Provider, Dsn6Provider, DscifProvider } from './volume';
import { StateTransforms } from '../transforms';
import { MmcifProvider, PdbProvider, GroProvider } from './structure';
import { MmcifProvider, PdbProvider, GroProvider, Provider3dg } from './structure';
import msgpackDecode from '../../../mol-io/common/msgpack/decode'
import { PlyProvider } from './shape';
......@@ -55,6 +55,7 @@ export class DataFormatRegistry<D extends PluginStateObject.Data.Binary | Plugin
}
constructor() {
this.add('3dg', Provider3dg)
this.add('ccp4', Ccp4Provider)
this.add('dscif', DscifProvider)
this.add('dsn6', Dsn6Provider)
......
......@@ -69,7 +69,23 @@ export const GroProvider: DataFormatProvider<any> = {
}
}
type StructureFormat = 'pdb' | 'cif' | 'gro'
export const Provider3dg: DataFormatProvider<any> = {
label: '3DG',
description: '3DG',
stringExtensions: ['3dg'],
binaryExtensions: [],
isApplicable: (info: FileInfo, data: string) => {
return info.ext === '3dg'
},
getDefaultBuilder: (ctx: PluginContext, data: StateBuilder.To<PluginStateObject.Data.String>, options: DataFormatBuilderOptions, state: State) => {
return Task.create('3DG default builder', async taskCtx => {
const traj = createModelTree(data, '3dg');
await state.updateTree(options.visuals ? createStructureTree(ctx, traj, false) : traj).runInContext(taskCtx)
})
}
}
type StructureFormat = 'pdb' | 'cif' | 'gro' | '3dg'
//
......@@ -219,6 +235,9 @@ export function createModelTree(b: StateBuilder.To<PluginStateObject.Data.Binary
case 'gro':
parsed = b.apply(StateTransforms.Model.TrajectoryFromGRO);
break
case '3dg':
parsed = b.apply(StateTransforms.Model.TrajectoryFrom3DG);
break
default:
throw new Error('unsupported format')
}
......
......@@ -26,11 +26,14 @@ import { shapeFromPly } from '../../../mol-model-formats/shape/ply';
import { SymmetryOperator } from '../../../mol-math/geometry';
import { ensureSecondaryStructure } from './helpers';
import { Script } from '../../../mol-script/script';
import { parse3DG } from '../../../mol-io/reader/3dg/parser';
import { trajectoryFrom3DG } from '../../../mol-model-formats/structure/3dg';
export { TrajectoryFromBlob };
export { TrajectoryFromMmCif };
export { TrajectoryFromPDB };
export { TrajectoryFromGRO };
export { TrajectoryFrom3DG };
export { ModelFromTrajectory };
export { StructureFromTrajectory };
export { StructureFromModel };
......@@ -137,6 +140,24 @@ const TrajectoryFromGRO = PluginStateTransform.BuiltIn({
}
});
type TrajectoryFrom3DG = typeof TrajectoryFrom3DG
const TrajectoryFrom3DG = PluginStateTransform.BuiltIn({
name: 'trajectory-from-3dg',
display: { name: 'Parse 3DG', description: 'Parse 3DG string and create trajectory.' },
from: [SO.Data.String],
to: SO.Molecule.Trajectory
})({
apply({ a }) {
return Task.create('Parse 3DG', async ctx => {
const parsed = await parse3DG(a.data).runInContext(ctx);
if (parsed.isError) throw new Error(parsed.message);
const models = await trajectoryFrom3DG(parsed.result).runInContext(ctx);
const props = { label: `${models[0].entry}`, description: `${models.length} model${models.length === 1 ? '' : 's'}` };
return new SO.Molecule.Trajectory(models, props);
});
}
});
const plus1 = (v: number) => v + 1, minus1 = (v: number) => v - 1;
type ModelFromTrajectory = typeof ModelFromTrajectory
const ModelFromTrajectory = PluginStateTransform.BuiltIn({
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment