diff --git a/src/apps/cif2bcif/converter.ts b/src/apps/cif2bcif/converter.ts index 1a3a08221bdb79e9808e69dad4651aa141e2cd21..d885b3f62f6359211b63a31382feefbf6fd2a043 100644 --- a/src/apps/cif2bcif/converter.ts +++ b/src/apps/cif2bcif/converter.ts @@ -9,11 +9,10 @@ import CIF, { Category } from 'mol-io/reader/cif' import * as Encoder from 'mol-io/writer/cif' import * as fs from 'fs' import classify from './field-classifier' -import { Run } from 'mol-task' async function getCIF(path: string) { const str = fs.readFileSync(path, 'utf8'); - const parsed = await Run(CIF.parseText(str)); + const parsed = await CIF.parseText(str).run(); if (parsed.isError) { throw new Error(parsed.toString()); } diff --git a/src/apps/combine-mmcif/index.ts b/src/apps/combine-mmcif/index.ts index d107f81132f4110c1c4d01152711ba7f8a9155c5..205c55c11c748d752dd12033405a524fd6102b22 100644 --- a/src/apps/combine-mmcif/index.ts +++ b/src/apps/combine-mmcif/index.ts @@ -13,7 +13,7 @@ require('util.promisify').shim(); const readFile = util.promisify(fs.readFile); const writeFile = util.promisify(fs.writeFile); -import { Run, Progress } from 'mol-task' +import { Progress } from 'mol-task' import { Database, Table, DatabaseCollection } from 'mol-data/db' import CIF from 'mol-io/reader/cif' // import { CCD_Schema } from 'mol-io/reader/cif/schema/ccd' @@ -78,7 +78,7 @@ export async function getBIRD() { async function parseCif(data: string|Uint8Array) { const comp = CIF.parse(data); console.time('parse cif'); - const parsed = await Run(comp, p => console.log(Progress.format(p)), 250); + const parsed = await comp.run(p => console.log(Progress.format(p)), 250); console.timeEnd('parse cif'); if (parsed.isError) throw parsed; return parsed diff --git a/src/apps/render-test/state.ts b/src/apps/render-test/state.ts index 58f3404e7347b1632c2885754c8a57a20b0c865f..656074ce584ddfcb78843a2752810f7e1ff8891a 100644 --- a/src/apps/render-test/state.ts +++ b/src/apps/render-test/state.ts @@ -16,11 +16,10 @@ import Viewer from 'mol-view/viewer' import Spacefill, { SpacefillProps } from 'mol-geo/representation/structure/spacefill' import Point, { PointProps } from 'mol-geo/representation/structure/point' -import { Run } from 'mol-task' import { StructureSymmetry, Structure, Model } from 'mol-model/structure' // import mcubes from './utils/mcubes' -import { getModelFromPdbId, getModelFromFile, log, Volume, getVolumeFromEmdId } from './utils' +import { getModelFromPdbId, getModelFromFile, runTask, Volume, getVolumeFromEmdId } from './utils' import { StructureRepresentation } from 'mol-geo/representation/structure'; import { Color } from 'mol-util/color'; import Surface, { SurfaceProps } from 'mol-geo/representation/volume/surface'; @@ -110,7 +109,7 @@ export default class State { let structure: Structure const assemblies = model.symmetry.assemblies if (assemblies.length) { - structure = await Run(StructureSymmetry.buildAssembly(Structure.ofModel(model), assembly || '1'), log, 500) + structure = await runTask(StructureSymmetry.buildAssembly(Structure.ofModel(model), assembly || '1')); } else { structure = Structure.ofModel(model) } @@ -128,11 +127,11 @@ export default class State { if (!structure) return this.pointRepr = StructureRepresentation(Point) - await Run(this.pointRepr.create(structure, this.getPointProps()), log, 500) + await runTask(this.pointRepr.create(structure, this.getPointProps())) viewer.add(this.pointRepr) this.spacefillRepr = StructureRepresentation(Spacefill) - await Run(this.spacefillRepr.create(structure, this.getSpacefillProps()), log, 500) + await runTask(this.spacefillRepr.create(structure, this.getSpacefillProps())) viewer.add(this.spacefillRepr) this.updateVisibility() @@ -160,13 +159,13 @@ export default class State { if (this.surfaceRepr) this.viewer.remove(this.surfaceRepr) this.surfaceRepr = VolumeRepresentation(Surface) - await Run(this.surfaceRepr.create(v.volume, { + await runTask(this.surfaceRepr.create(v.volume, { isoValue: VolumeIsoValue.relative(v.volume.dataStats, 3.0), alpha: 0.5, flatShaded: false, flipSided: true, doubleSided: true - }), log, 500) + })) viewer.add(this.surfaceRepr) viewer.requestDraw() @@ -197,8 +196,8 @@ export default class State { async update () { if (!this.spacefillRepr) return - await Run(this.spacefillRepr.update(this.getSpacefillProps()), log, 500) - await Run(this.pointRepr.update(this.getPointProps()), log, 500) + await runTask(this.spacefillRepr.update(this.getSpacefillProps())) + await runTask(this.pointRepr.update(this.getPointProps())) this.viewer.add(this.spacefillRepr) this.viewer.add(this.pointRepr) this.viewer.update() diff --git a/src/apps/render-test/utils/index.ts b/src/apps/render-test/utils/index.ts index b5eb271c7a63815185263d5e7185934d33b4ed12..db2b732afdeee394a0d026b6ee8010800834f9db 100644 --- a/src/apps/render-test/utils/index.ts +++ b/src/apps/render-test/utils/index.ts @@ -5,7 +5,7 @@ */ import CIF from 'mol-io/reader/cif' -import { Run, Progress } from 'mol-task' +import { Progress, Task } from 'mol-task' import { Model } from 'mol-model/structure' import { VolumeData, parseDensityServerData } from 'mol-model/volume' import { DensityServer_Data_Database } from 'mol-io/reader/cif/schema/density-server'; @@ -15,6 +15,10 @@ export function log(progress: Progress) { console.log(`${p.message} ${(p.current/p.max*100).toFixed(2)}%`) } +export function runTask<T>(task: Task<T>) { + return task.run(log, 500); +} + export async function downloadCif(url: string, isBinary: boolean) { const data = await fetch(url); return parseCif(isBinary ? new Uint8Array(await data.arrayBuffer()) : await data.text()); @@ -22,14 +26,14 @@ export async function downloadCif(url: string, isBinary: boolean) { export async function parseCif(data: string|Uint8Array) { const comp = CIF.parse(data) - const parsed = await Run(comp, log, 500); + const parsed = await comp.run(log, 500); if (parsed.isError) throw parsed; return parsed.result } export async function getModelFromPdbId(pdbid: string) { const cif = await downloadCif(`https://files.rcsb.org/download/${pdbid}.cif`, false) - return Run(Model.create({ kind: 'mmCIF', data: CIF.schema.mmCIF(cif.blocks[0]) })) + return Model.create({ kind: 'mmCIF', data: CIF.schema.mmCIF(cif.blocks[0]) }).run(); } const readFileAsText = (file: File) => { @@ -46,7 +50,7 @@ const readFileAsText = (file: File) => { export async function getModelFromFile(file: File) { const cif = await parseCif(await readFileAsText(file)) - return Run(Model.create({ kind: 'mmCIF', data: CIF.schema.mmCIF(cif.blocks[0]) })) + return Model.create({ kind: 'mmCIF', data: CIF.schema.mmCIF(cif.blocks[0]) }).run(); } export type Volume = { source: DensityServer_Data_Database, volume: VolumeData } @@ -54,5 +58,5 @@ export type Volume = { source: DensityServer_Data_Database, volume: VolumeData } export async function getVolumeFromEmdId(emdid: string): Promise<Volume> { const cif = await downloadCif(`https://webchem.ncbr.muni.cz/DensityServer/em/emd-${emdid}/cell?detail=4`, true) const data = CIF.schema.densityServer(cif.blocks[1]) - return { source: data, volume: await Run(parseDensityServerData(data)) } + return { source: data, volume: await parseDensityServerData(data).run() } } \ No newline at end of file diff --git a/src/apps/render-test/utils/mcubes.ts b/src/apps/render-test/utils/mcubes.ts index 92905c7b6f5d111486ee7a1bd6fab7b95a5cd5e6..f74859d8b157afd0675a51a4c8deb2c0a8571b16 100644 --- a/src/apps/render-test/utils/mcubes.ts +++ b/src/apps/render-test/utils/mcubes.ts @@ -4,7 +4,6 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { Run } from 'mol-task' import { computeMarchingCubes } from 'mol-geo/util/marching-cubes/algorithm' import { Mesh } from 'mol-geo/shape/mesh' import { Tensor, Mat4, Vec3 } from 'mol-math/linear-algebra' @@ -38,11 +37,11 @@ export default async function computeSurface(f: (x: number, y: number, z: number const min = Vec3.create(-1.1, -1.1, -1.1), max = Vec3.create(1.1, 1.1, 1.1); fillField(field, f, min, max); - const surface = await Run(computeMarchingCubes({ + const surface = await computeMarchingCubes({ scalarField: field, isoLevel: 0, oldSurface: data ? data.surface : void 0 - })); + }).run(); const translation = Mat4.fromTranslation(Mat4.zero(), min); const grid = Vec3.zero(); diff --git a/src/apps/schema-generator/schema-from-mmcif-dic.ts b/src/apps/schema-generator/schema-from-mmcif-dic.ts index a6fc5fed2b9cc9a0a022055f77ded38923d5e82e..c9149a2c8f29a56d3f4468db23dc5a3dbe7b59a0 100644 --- a/src/apps/schema-generator/schema-from-mmcif-dic.ts +++ b/src/apps/schema-generator/schema-from-mmcif-dic.ts @@ -14,15 +14,14 @@ import CIF, { Frame } from 'mol-io/reader/cif' import { generateSchema } from './util/cif-dic' import { generate } from './util/generate' import { Filter } from './util/json-schema' -import { Run } from 'mol-task' async function runGenerateSchema(name: string, fieldNamesPath?: string, typescript = false, out?: string) { await ensureMmcifDicAvailable() - const mmcifDic = await Run(CIF.parseText(fs.readFileSync(MMCIF_DIC_PATH, 'utf8'))); + const mmcifDic = await CIF.parseText(fs.readFileSync(MMCIF_DIC_PATH, 'utf8')).run(); if (mmcifDic.isError) throw mmcifDic await ensureIhmDicAvailable() - const ihmDic = await Run(CIF.parseText(fs.readFileSync(IHM_DIC_PATH, 'utf8'))); + const ihmDic = await CIF.parseText(fs.readFileSync(IHM_DIC_PATH, 'utf8')).run(); if (ihmDic.isError) throw ihmDic const mmcifDicVersion = CIF.schema.dic(mmcifDic.result.blocks[0]).dictionary.version.value(0) @@ -44,7 +43,7 @@ async function runGenerateSchema(name: string, fieldNamesPath?: string, typescri async function getFieldNamesFilter(fieldNamesPath: string): Promise<Filter> { const fieldNamesStr = fs.readFileSync(fieldNamesPath, 'utf8') - const parsed = await Run(Csv(fieldNamesStr, { noColumnNames: true })); + const parsed = await Csv(fieldNamesStr, { noColumnNames: true }).run(); if (parsed.isError) throw parser.error const csvFile = parsed.result; diff --git a/src/apps/structure-info/helpers.ts b/src/apps/structure-info/helpers.ts index 94095a99055759cdbab8d9b2c677345632520848..f4a86d9a67ac824988e4fbe0fffd13ced8b2aac5 100644 --- a/src/apps/structure-info/helpers.ts +++ b/src/apps/structure-info/helpers.ts @@ -10,7 +10,7 @@ import fetch from 'node-fetch' require('util.promisify').shim(); import CIF from 'mol-io/reader/cif' -import { Run, Progress } from 'mol-task' +import { Progress } from 'mol-task' const readFileAsync = util.promisify(fs.readFile); @@ -27,7 +27,7 @@ async function readFile(path: string) { async function parseCif(data: string|Uint8Array) { const comp = CIF.parse(data); - const parsed = await Run(comp, p => console.log(Progress.format(p)), 250); + const parsed = await comp.run(p => console.log(Progress.format(p)), 250); if (parsed.isError) throw parsed; return parsed.result; } diff --git a/src/apps/structure-info/model.ts b/src/apps/structure-info/model.ts index 3f7957df85e57f94552e10188669cb6059f5d30d..ad61b5d13df2923b83ad95302ea505b80051542d 100644 --- a/src/apps/structure-info/model.ts +++ b/src/apps/structure-info/model.ts @@ -16,7 +16,6 @@ import { OrderedSet } from 'mol-data/int'; import { Table } from 'mol-data/db'; import { mmCIF_Database } from 'mol-io/reader/cif/schema/mmcif'; import { openCif, downloadCif } from './helpers'; -import { Run } from 'mol-task'; async function downloadFromPdb(pdb: string) { @@ -118,7 +117,7 @@ export function printIHMModels(model: Model) { } async function run(mmcif: mmCIF_Database) { - const models = await Run(Model.create({ kind: 'mmCIF', data: mmcif })); + const models = await Model.create({ kind: 'mmCIF', data: mmcif }).run(); const structure = Structure.ofModel(models[0]); printSequence(models[0]); printIHMModels(models[0]); diff --git a/src/apps/structure-info/volume.ts b/src/apps/structure-info/volume.ts index 325e268dd7779e311408fe7c72280b6a7acac48c..00dd391711eba424686f5825594056426ac04380 100644 --- a/src/apps/structure-info/volume.ts +++ b/src/apps/structure-info/volume.ts @@ -12,7 +12,6 @@ import { VolumeData, parseDensityServerData, VolumeIsoValue } from 'mol-model/vo import { downloadCif } from './helpers' import CIF from 'mol-io/reader/cif' import { DensityServer_Data_Database } from 'mol-io/reader/cif/schema/density-server'; -import { Run } from 'mol-task'; import { Table } from 'mol-data/db'; import { computeVolumeSurface } from 'mol-geo/representation/volume/surface'; import { StringBuilder } from 'mol-util'; @@ -25,7 +24,7 @@ type Volume = { source: DensityServer_Data_Database, volume: VolumeData } async function getVolume(url: string): Promise<Volume> { const cif = await downloadCif(url, true); const data = CIF.schema.densityServer(cif.blocks[1]); - return { source: data, volume: await Run(parseDensityServerData(data)) }; + return { source: data, volume: await parseDensityServerData(data).run() }; } function print(data: Volume) { @@ -38,7 +37,7 @@ function print(data: Volume) { } async function doMesh(data: Volume, filename: string) { - const mesh = await Run(computeVolumeSurface(data.volume, VolumeIsoValue.relative(data.volume.dataStats, 1.5))); + const mesh = await computeVolumeSurface(data.volume, VolumeIsoValue.relative(data.volume.dataStats, 1.5)).run(); console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount }); // Export the mesh in OBJ format. diff --git a/src/examples/task.ts b/src/examples/task.ts index 41025f042c48eb1252f14483ba94e1f10c771470..64143cfb7da152845fa702b6854eb0c5f677c018 100644 --- a/src/examples/task.ts +++ b/src/examples/task.ts @@ -4,11 +4,11 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { Task, Run, Progress, Scheduler, now, MultistepTask, chunkedSubtask } from 'mol-task' +import { Task, Progress, Scheduler, now, MultistepTask, chunkedSubtask } from 'mol-task' export async function test1() { const t = Task.create('test', async () => 1); - const r = await Run(t); + const r = await t.run(); console.log(r); } @@ -53,9 +53,9 @@ export function testTree() { if (ctx.shouldUpdate) await ctx.update('hi! 3'); // ctx.update('Running children...', true); - const c1 = ctx.runChild(createTask(250, 1)); - const c2 = ctx.runChild(createTask(500, 2)); - const c3 = ctx.runChild(createTask(750, 3)); + const c1 = createTask(250, 1).runAsChild(ctx); + const c2 = createTask(500, 2).runAsChild(ctx); + const c3 = createTask(750, 3).runAsChild(ctx); //await ctx.runChild(abortAfter(350)); @@ -87,8 +87,8 @@ export const ms = MultistepTask('ms-task', ['step 1', 'step 2', 'step 3'], async const s = await chunkedSubtask(ctx, 25, { i: 0, current: 0, total: 125 }, processChunk, (ctx, s, p) => ctx.update('chunk test ' + p)) return s.i; }); - - await ctx.runChild(child); + + await child.runAsChild(ctx); await Scheduler.delay(250); await step(1); await chunkedSubtask(ctx, 25, { i: 0, current: 0, total: 80 }, processChunk, (ctx, s, p) => ctx.update('chunk test ' + p)) @@ -114,7 +114,7 @@ async function test() { //const r = await Run(testTree(), abortingObserver, 250); //console.log(r); - const m = await Run(ms({ i: 10 }), logP); + const m = await ms({ i: 10 }).run(logP); console.log(m); } catch (e) { console.error(e); diff --git a/src/mol-geo/representation/structure/index.ts b/src/mol-geo/representation/structure/index.ts index 774ea8b077f18059c09e50f7563221a9392d4540..363e1771ed7ff49ddb907967511e6123f4769410 100644 --- a/src/mol-geo/representation/structure/index.ts +++ b/src/mol-geo/representation/structure/index.ts @@ -42,7 +42,7 @@ export function StructureRepresentation<P>(reprCtor: () => UnitsRepresentation<P const group = groups[i]; const repr = reprCtor() groupReprs.push({ repr, group }) - await ctx.runChild(repr.create(group, props), { message: 'Building structure unit representations...', current: i, max: groups.length }); + await repr.create(group, props).runAsChild(ctx, { message: 'Building structure unit representations...', current: i, max: groups.length }); renderObjects.push(...repr.renderObjects) } }); @@ -55,8 +55,8 @@ export function StructureRepresentation<P>(reprCtor: () => UnitsRepresentation<P const groupRepr = groupReprs[i] const { repr, group } = groupRepr const state = { message: 'Updating structure unit representations...', current: i, max: il }; - if (!await ctx.runChild(repr.update(props), state)) { - await ctx.runChild(repr.create(group, props), state) + if (!await repr.update(props).runAsChild(ctx, state)) { + await repr.create(group, props).runAsChild(ctx, state) } renderObjects.push(...repr.renderObjects) } diff --git a/src/mol-geo/representation/structure/spacefill.ts b/src/mol-geo/representation/structure/spacefill.ts index db82405148603f4167fc66e3a9f7deaba9f872f4..7f2b7ab722ffe1911b2cb70cc8de332bb98fb8b1 100644 --- a/src/mol-geo/representation/structure/spacefill.ts +++ b/src/mol-geo/representation/structure/spacefill.ts @@ -83,8 +83,7 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> { const { detail, colorTheme, alpha, visible, doubleSided } = { ...DefaultSpacefillProps, ...props } - await ctx.update('Computing spacefill mesh'); - const mesh = await ctx.runChild(createSpacefillMesh(group.units[0], detail)) + const mesh = await createSpacefillMesh(group.units[0], detail).runAsChild(ctx, 'Computing spacefill mesh') // console.log(mesh) const vertexMap = VertexMap.fromMesh(mesh) diff --git a/src/mol-geo/representation/volume/index.ts b/src/mol-geo/representation/volume/index.ts index 84aee724fff635612391ba5d63db2f2df2e8f55e..779c05940b96e083a7e308479f76d010deaa7e79 100644 --- a/src/mol-geo/representation/volume/index.ts +++ b/src/mol-geo/representation/volume/index.ts @@ -29,8 +29,7 @@ export function VolumeRepresentation<P>(reprCtor: () => VolumeElementRepresentat create(volumeData: VolumeData, props: P = {} as P) { return Task.create('VolumeRepresentation.create', async ctx => { const repr = reprCtor() - await ctx.update({ message: 'Building volume representation...', current: 0, max: 1 }); - await ctx.runChild(repr.create(volumeData, props)); + await repr.create(volumeData, props).runAsChild(ctx, { message: 'Building volume representation...', current: 0, max: 1 }); renderObjects.push(...repr.renderObjects) }); }, diff --git a/src/mol-geo/representation/volume/surface.ts b/src/mol-geo/representation/volume/surface.ts index a2de1a61d10cef902ee848ee9efb6ddab6572ead..bc9531ead7527fed500969d8bf22aa1a966c2c9f 100644 --- a/src/mol-geo/representation/volume/surface.ts +++ b/src/mol-geo/representation/volume/surface.ts @@ -20,10 +20,10 @@ export function computeVolumeSurface(volume: VolumeData, isoValue: VolumeIsoValu return Task.create<Mesh>('Volume Surface', async ctx => { ctx.update({ message: 'Marching cubes...' }); - const mesh = await ctx.runChild(computeMarchingCubes({ + const mesh = await computeMarchingCubes({ isoLevel: VolumeIsoValue.toAbsolute(isoValue).absoluteValue, scalarField: volume.data - })); + }).runAsChild(ctx); const transform = VolumeData.getGridToCartesianTransform(volume); ctx.update({ message: 'Transforming mesh...' }); @@ -56,7 +56,7 @@ export default function Surface(): VolumeElementRepresentation<SurfaceProps> { curProps = { ...DefaultSurfaceProps, ...props } const { alpha, visible, flatShaded, flipSided, doubleSided } = curProps - const mesh = await ctx.runChild(computeVolumeSurface(volume, curProps.isoValue)) + const mesh = await computeVolumeSurface(volume, curProps.isoValue).runAsChild(ctx) if (!flatShaded) { Mesh.computeNormalsImmediate(mesh) } diff --git a/src/mol-io/reader/_spec/csv.spec.ts b/src/mol-io/reader/_spec/csv.spec.ts index b074b5bc7d51a2df190180065852e4f7dec8c75d..0802bc7491fedc90c702ef6bc24d7fa653746895 100644 --- a/src/mol-io/reader/_spec/csv.spec.ts +++ b/src/mol-io/reader/_spec/csv.spec.ts @@ -5,7 +5,6 @@ */ import Csv from '../csv/parser' -import { Run } from 'mol-task'; const csvStringBasic = `StrCol,IntCol,FloatCol # comment @@ -24,7 +23,7 @@ string2\t42\t2.44` describe('csv reader', () => { it('basic', async () => { - const parsed = await Run(Csv(csvStringBasic)); + const parsed = await Csv(csvStringBasic).run(); if (parsed.isError) return; const csvFile = parsed.result; @@ -46,7 +45,7 @@ describe('csv reader', () => { }); it('advanced', async () => { - const parsed = await Run(Csv(csvStringAdvanced)); + const parsed = await Csv(csvStringAdvanced).run(); if (parsed.isError) return; const csvFile = parsed.result; @@ -63,7 +62,7 @@ describe('csv reader', () => { }); it('tabs', async () => { - const parsed = await Run(Csv(tabString, { delimiter: '\t' })); + const parsed = await Csv(tabString, { delimiter: '\t' }).run();; if (parsed.isError) return; const csvFile = parsed.result; diff --git a/src/mol-io/reader/_spec/gro.spec.ts b/src/mol-io/reader/_spec/gro.spec.ts index 6254be8f9d45d287f643e2d50993e8b62eb11bbe..055e4e61b227a58a86c5a1b4b6317c996558ec98 100644 --- a/src/mol-io/reader/_spec/gro.spec.ts +++ b/src/mol-io/reader/_spec/gro.spec.ts @@ -6,7 +6,6 @@ */ import Gro from '../gro/parser' -import { Run } from 'mol-task'; const groString = `MD of 2 waters, t= 4.2 6 @@ -27,7 +26,7 @@ const groStringHighPrecision = `Generated by trjconv : 2168 system t= 15.00000 describe('gro reader', () => { it('basic', async () => { - const parsed = await Run(Gro(groString)); + const parsed = await Gro(groString).run(); if (parsed.isError) { console.log(parsed) @@ -58,7 +57,7 @@ describe('gro reader', () => { }); it('high precision', async () => { - const parsed = await Run(Gro(groStringHighPrecision)); + const parsed = await Gro(groStringHighPrecision).run(); if (parsed.isError) { console.log(parsed) diff --git a/src/mol-io/reader/_spec/mol2.spec.ts b/src/mol-io/reader/_spec/mol2.spec.ts index 43244780636af6fbcd75010522ba9405b75ca2ff..dc88b16043caf6777ca6571656f2c3cfab6eb38f 100644 --- a/src/mol-io/reader/_spec/mol2.spec.ts +++ b/src/mol-io/reader/_spec/mol2.spec.ts @@ -1,6 +1,5 @@ import Mol2 from '../mol2/parser' -import { Run } from 'mol-task'; const Mol2String = `@<TRIPOS>MOLECULE 5816 @@ -247,7 +246,7 @@ GASTEIGER describe('mol2 reader', () => { it('basic', async () => { - const parsed = await Run(Mol2(Mol2String)); + const parsed = await Mol2(Mol2String).run(); if (parsed.isError) { throw new Error(parsed.message); } @@ -298,7 +297,7 @@ describe('mol2 reader', () => { }); it('multiblocks', async () => { - const parsed = await Run(Mol2(Mol2StringMultiBlocks)); + const parsed = await Mol2(Mol2StringMultiBlocks).run(); if (parsed.isError) { throw new Error(parsed.message); } @@ -349,7 +348,7 @@ describe('mol2 reader', () => { }); it('minimal', async () => { - const parsed = await Run(Mol2(Mol2StringMinimal)); + const parsed = await Mol2(Mol2StringMinimal).run(); if (parsed.isError) { throw new Error(parsed.message); } diff --git a/src/mol-model/structure/structure/symmetry.ts b/src/mol-model/structure/structure/symmetry.ts index bf17c9013887a9f910257183ee3a2bfc99870826..4a0abaf78eacd46439cbf61a69b5ad97b3ea19c6 100644 --- a/src/mol-model/structure/structure/symmetry.ts +++ b/src/mol-model/structure/structure/symmetry.ts @@ -26,7 +26,7 @@ namespace StructureSymmetry { const assembler = Structure.Builder(); for (const g of assembly.operatorGroups) { - const selection = await ctx.runChild(g.selector(structure)); + const selection = await g.selector(structure).runAsChild(ctx); if (Selection.structureCount(selection) === 0) { continue; } diff --git a/src/mol-task/execution/observable.ts b/src/mol-task/execution/observable.ts index 82d4e05a43917365d625115cdd1b13c072346d88..4f451628759827ebebb7fca9f2988f1727d45f11 100644 --- a/src/mol-task/execution/observable.ts +++ b/src/mol-task/execution/observable.ts @@ -10,13 +10,22 @@ import { Progress } from './progress' import { now } from '../util/now' import { Scheduler } from '../util/scheduler' -function ExecuteObservable<T>(task: Task<T>, observer: Progress.Observer, updateRateMs = 250) { +interface ExposedTask<T> extends Task<T> { + f: (ctx: RuntimeContext) => Promise<T>, + onAbort?: () => void +} + +export function ExecuteObservable<T>(task: Task<T>, observer: Progress.Observer, updateRateMs = 250) { const info = ProgressInfo(task, observer, updateRateMs); const ctx = new ObservableRuntimeContext(info, info.root); - return execute(task, ctx); + return execute(task as ExposedTask<T>, ctx); +} + +export function ExecuteObservableChild<T>(ctx: RuntimeContext, task: Task<T>, progress?: string | Partial<RuntimeContext.ProgressUpdate>) { + return (ctx as ObservableRuntimeContext).runChild(task, progress); } -namespace ExecuteObservable { +export namespace ExecuteObservable { export let PRINT_ERRORS_TO_STD_ERR = false; } @@ -77,10 +86,10 @@ function snapshotProgress(info: ProgressInfo): Progress { return { root: cloneTree(info.root), canAbort: canAbort(info.root), requestAbort: info.tryAbort }; } -async function execute<T>(task: Task<T>, ctx: ObservableRuntimeContext) { +async function execute<T>(task: ExposedTask<T>, ctx: ObservableRuntimeContext) { ctx.node.progress.startedTime = now(); try { - const ret = await task.__f(ctx); + const ret = await task.f(ctx); if (ctx.info.abortToken.abortRequested) { abort(ctx.info, ctx.node); } @@ -91,7 +100,7 @@ async function execute<T>(task: Task<T>, ctx: ObservableRuntimeContext) { if (ctx.node.children.length > 0) { await new Promise(res => { ctx.onChildrenFinished = res; }); } - if (task.__onAbort) task.__onAbort(); + if (task.onAbort) task.onAbort(); } if (ExecuteObservable.PRINT_ERRORS_TO_STD_ERR) console.error(e); throw e; @@ -197,7 +206,7 @@ class ObservableRuntimeContext implements RuntimeContext { children.push(node); const ctx = new ObservableRuntimeContext(this.info, node); try { - return await execute(task, ctx); + return await execute(task as ExposedTask<T>, ctx); } catch (e) { if (Task.isAbort(e)) { // need to catch the error here because otherwise @@ -223,6 +232,4 @@ class ObservableRuntimeContext implements RuntimeContext { this.node = node; this.info = info; } -} - -export { ExecuteObservable } \ No newline at end of file +} \ No newline at end of file diff --git a/src/mol-task/execution/runtime-context.ts b/src/mol-task/execution/runtime-context.ts index d2529a3eb3599d9ece65c7183b7a36cdc0117b33..d0469abcfe65c408f321087e40170791c19c4176 100644 --- a/src/mol-task/execution/runtime-context.ts +++ b/src/mol-task/execution/runtime-context.ts @@ -4,8 +4,6 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { Task } from '../task' - interface RuntimeContext { readonly shouldUpdate: boolean, readonly isSynchronous: boolean, @@ -15,11 +13,7 @@ interface RuntimeContext { // // Alternatively, progress can be updated without notifying (and yielding) using update(progress, true). // This is useful for nested tasks. - update(progress?: string | Partial<RuntimeContext.ProgressUpdate>, dontNotify?: boolean): Promise<void> | void, - - // Run a child task that adds a new node to the progress tree. - // Allow to pass the progress so that the progress tree can be kept in a "good state" without having to separately call update. - runChild<T>(task: Task<T>, progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<T> + update(progress?: string | Partial<RuntimeContext.ProgressUpdate>, dontNotify?: boolean): Promise<void> | void } namespace RuntimeContext { diff --git a/src/mol-task/execution/synchronous.ts b/src/mol-task/execution/synchronous.ts index 4ca40a04a5ccc91024b08ca3bcf6093ac8643e34..5c729a61097f58d47d00619901f00487dcc282df 100644 --- a/src/mol-task/execution/synchronous.ts +++ b/src/mol-task/execution/synchronous.ts @@ -4,21 +4,12 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { Task } from '../task' import { RuntimeContext } from './runtime-context' class SynchronousRuntimeContext implements RuntimeContext { shouldUpdate = false; isSynchronous = true; - update(progress: string | Partial<RuntimeContext.ProgressUpdate>, dontNotify?: boolean): Promise<void> | void { } - runChild<T>(task: Task<T>, progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<T> { return ExecuteSynchronous(task); } -} - -const SyncRuntimeInstance = new SynchronousRuntimeContext(); - -function ExecuteSynchronous<T>(task: Task<T>) { - return task.__f(SyncRuntimeInstance); } -export { ExecuteSynchronous } \ No newline at end of file +export const SyncRuntimeContext = new SynchronousRuntimeContext(); \ No newline at end of file diff --git a/src/mol-task/index.ts b/src/mol-task/index.ts index 830153c1cfaa3cd6512b083dd988b90b825bdb08..2ef6489c9fffe85d67739274d1aab599dae14de9 100644 --- a/src/mol-task/index.ts +++ b/src/mol-task/index.ts @@ -6,21 +6,10 @@ import { Task } from './task' import { RuntimeContext } from './execution/runtime-context' -import { ExecuteSynchronous } from './execution/synchronous' -import { ExecuteObservable } from './execution/observable' import { Progress } from './execution/progress' import { now } from './util/now' import { Scheduler } from './util/scheduler' import { MultistepTask } from './util/multistep' import { chunkedSubtask } from './util/chunked' -// Run the task without the ability to observe its progress. -function Run<T>(task: Task<T>): Promise<T>; -// Run the task with the ability to observe its progress and request cancellation. -function Run<T>(task: Task<T>, observer: Progress.Observer, updateRateMs?: number): Promise<T>; -function Run<T>(task: Task<T>, observer?: Progress.Observer, updateRateMs?: number): Promise<T> { - if (observer) return ExecuteObservable(task, observer, updateRateMs || 250); - return ExecuteSynchronous(task); -} - -export { Task, RuntimeContext, Progress, Run, now, Scheduler, MultistepTask, chunkedSubtask } \ No newline at end of file +export { Task, RuntimeContext, Progress, now, Scheduler, MultistepTask, chunkedSubtask } \ No newline at end of file diff --git a/src/mol-task/task.ts b/src/mol-task/task.ts index 0ce5ca40bf65ef59de655b3ecdf39d4a2b12abec..34dc4556373cc1b7afb381f7d6b56dd7c100d1cf 100644 --- a/src/mol-task/task.ts +++ b/src/mol-task/task.ts @@ -5,25 +5,51 @@ */ import { RuntimeContext } from './execution/runtime-context' +import { Progress } from './execution/progress' +import { ExecuteObservable, ExecuteObservableChild } from './execution/observable'; +import { SyncRuntimeContext } from 'mol-task/execution/synchronous'; // A "named function wrapper" with built in "computation tree progress tracking". // Use Run(t, ?observer, ?updateRate) to execute interface Task<T> { + // run the task without observation + run(): Promise<T>, + // run the task with the specified observer, default updateRate is 250ms + run(observer: Progress.Observer, updateRateMs?: number): Promise<T>, + + // Run a child task that adds a new node to the progress tree. + // Allow to pass the progress so that the progress tree can be kept in a "good state" without having to separately call update. + runAsChild(ctx: RuntimeContext, progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<T> + readonly id: number, - readonly name: string, - // Do not call this directly, use Run. - readonly __f: (ctx: RuntimeContext) => Promise<T>, - // Do not call this directly, use Run. - readonly __onAbort: (() => void) | undefined + readonly name: string } namespace Task { + class Impl<T> implements Task<T> { + readonly id: number; + + run(observer?: Progress.Observer, updateRateMs?: number): Promise<T> { + if (observer) return ExecuteObservable(this, observer, updateRateMs as number || 250); + return this.f(SyncRuntimeContext); + } + + runAsChild(ctx: RuntimeContext, progress?: string | Partial<RuntimeContext.ProgressUpdate>): Promise<T> { + if (ctx.isSynchronous) return this.f(SyncRuntimeContext); + return ExecuteObservableChild(ctx, this, progress as string | Partial<RuntimeContext.ProgressUpdate>); + } + + constructor(public name: string, public f: (ctx: RuntimeContext) => Promise<T>, public onAbort?: () => void) { + this.id = nextId(); + } + } + export interface Aborted { isAborted: true, reason: string } export function isAbort(e: any): e is Aborted { return !!e && !!e.isAborted; } export function Aborted(reason: string): Aborted { return { isAborted: true, reason }; } export function create<T>(name: string, f: (ctx: RuntimeContext) => Promise<T>, onAbort?: () => void): Task<T> { - return { id: nextId(), name, __f: f, __onAbort: onAbort }; + return new Impl(name, f, onAbort); } export function constant<T>(name: string, value: T): Task<T> { return create(name, async ctx => value); } diff --git a/src/perf-tests/lookup3d.ts b/src/perf-tests/lookup3d.ts index 1245d80d4cf4f2509d15316fa9871aae83aa54e6..3b52eee9f0e027d48f6113ae3551a3d42e922038 100644 --- a/src/perf-tests/lookup3d.ts +++ b/src/perf-tests/lookup3d.ts @@ -4,7 +4,6 @@ import CIF from 'mol-io/reader/cif' import { Structure, Model } from 'mol-model/structure' -import { Run } from 'mol-task'; import { GridLookup3D } from 'mol-math/geometry'; // import { sortArray } from 'mol-data/util'; import { OrderedSet } from 'mol-data/int'; @@ -27,14 +26,14 @@ async function readData(path: string) { export async function readCIF(path: string) { const input = await readData(path) const comp = typeof input === 'string' ? CIF.parseText(input) : CIF.parseBinary(input); - const parsed = await Run(comp); + const parsed = await comp.run(); if (parsed.isError) { throw parsed; } const data = parsed.result.blocks[0]; const mmcif = CIF.schema.mmCIF(data); - const models = await Run(Model.create({ kind: 'mmCIF', data: mmcif })); + const models = await Model.create({ kind: 'mmCIF', data: mmcif }).run(); const structures = models.map(Structure.ofModel); return { mmcif, models, structures }; diff --git a/src/perf-tests/structure.ts b/src/perf-tests/structure.ts index e859ff78eb862628727f5d66f17d11a20195123e..2ad787c4ac9b2d1416a78fb73f5ac92cc3fdb44d 100644 --- a/src/perf-tests/structure.ts +++ b/src/perf-tests/structure.ts @@ -15,7 +15,6 @@ import { Structure, Model, Queries as Q, Element, Selection, StructureSymmetry, //import { Segmentation, OrderedSet } from 'mol-data/int' import to_mmCIF from 'mol-model/structure/export/mmcif' -import { Run } from 'mol-task'; import { Vec3 } from 'mol-math/linear-algebra'; //import { EquivalenceClasses } from 'mol-data/util'; @@ -62,7 +61,7 @@ export async function readCIF(path: string) { console.time('parse'); const comp = typeof input === 'string' ? CIF.parseText(input) : CIF.parseBinary(input); - const parsed = await Run(comp); + const parsed = await comp.run(); console.timeEnd('parse'); if (parsed.isError) { throw parsed; @@ -74,7 +73,7 @@ export async function readCIF(path: string) { console.timeEnd('schema') console.time('buildModels') - const models = await Run(Model.create({ kind: 'mmCIF', data: mmcif })); + const models = await Model.create({ kind: 'mmCIF', data: mmcif }).run(); console.timeEnd('buildModels') const structures = models.map(Structure.ofModel); @@ -292,7 +291,7 @@ export namespace PropertyAccess { export async function testAssembly(id: string, s: Structure) { console.time('assembly') - const a = await Run(StructureSymmetry.buildAssembly(s, '1')); + const a = await StructureSymmetry.buildAssembly(s, '1').run(); //const auth_comp_id = Q.props.residue.auth_comp_id; //const q1 = Query(Q.generators.atoms({ residueTest: l => auth_comp_id(l) === 'ALA' })); //const alas = await query(q1, a); @@ -305,7 +304,7 @@ export namespace PropertyAccess { export async function testSymmetry(id: string, s: Structure) { console.time('symmetry') - const a = await Run(StructureSymmetry.buildSymmetryRange(s, Vec3.create(-1, -1, -1), Vec3.create(1, 1, 1))); + const a = await StructureSymmetry.buildSymmetryRange(s, Vec3.create(-1, -1, -1), Vec3.create(1, 1, 1)).run(); //const auth_comp_id = Q.props.residue.auth_comp_id; //const q1 = Query(Q.generators.atoms({ residueTest: l => auth_comp_id(l) === 'ALA' })); //const alas = await query(q1, a); @@ -336,7 +335,7 @@ export namespace PropertyAccess { // } function query(q: Query, s: Structure) { - return Run((q(s))); + return q(s).run(); } export async function run() {