diff --git a/packages/epanet-engine/package.json b/packages/epanet-engine/package.json index 331a66e..bb3535c 100644 --- a/packages/epanet-engine/package.json +++ b/packages/epanet-engine/package.json @@ -1,6 +1,6 @@ { "name": "@model-create/epanet-engine", - "version": "0.2.0", + "version": "0.3.0", "description": "", "main": "dist/index.js", "module": "dist/index.es6.js", diff --git a/packages/epanet-js/package.json b/packages/epanet-js/package.json index bf59246..838a859 100644 --- a/packages/epanet-js/package.json +++ b/packages/epanet-js/package.json @@ -1,5 +1,5 @@ { - "version": "0.2.0", + "version": "0.3.0", "license": "MIT", "main": "dist/index.js", "typings": "dist/index.d.ts", @@ -20,7 +20,7 @@ "doc": "tsdx build && yarn api-extractor run --local --verbose && mv ./temp/epanet-js.api.json ./input/ && yarn api-documenter markdown" }, "dependencies": { - "@model-create/epanet-engine": "0.2.0" + "@model-create/epanet-engine": "0.3.0" }, "peerDependencies": {}, "husky": { diff --git a/packages/epanet-js/src/OutputReader/index.ts b/packages/epanet-js/src/OutputReader/index.ts new file mode 100644 index 0000000..2496a44 --- /dev/null +++ b/packages/epanet-js/src/OutputReader/index.ts @@ -0,0 +1,185 @@ +enum NodeResultTypes { + Demand, + Head, + Pressure, + WaterQuality, +} + +enum LinkResultTypes { + Flow, + Velcoity, + Headloss, + AvgWaterQuality, + Status, + Setting, + ReactionRate, + Friction, +} + +export interface LinkResults { + flow: number[]; + velcoity: number[]; + headloss: number[]; + avgWaterQuality: number[]; + status: number[]; + setting: number[]; + reactionRate: number[]; + friction: number[]; +} + +export interface NodeResults { + demand: number[]; + head: number[]; + pressure: number[]; + waterQuality: number[]; +} + +export interface EpanetProlog { + nodeCount: number; + resAndTankCount: number; + linkCount: number; + pumpCount: number; + valveCount: number; + reportingPeriods: number; +} + +export interface EpanetResults { + prolog: EpanetProlog; + results: { + nodes: NodeResults[]; + links: LinkResults[]; + }; +} + +export function readBinary(results: Uint8Array): EpanetResults { + const view1 = new DataView(results.buffer); + const prolog: EpanetProlog = { + nodeCount: view1.getInt32(8, true), + resAndTankCount: view1.getInt32(12, true), + linkCount: view1.getInt32(16, true), + pumpCount: view1.getInt32(20, true), + valveCount: view1.getInt32(24, true), + reportingPeriods: view1.getInt32(results.byteLength - 12, true), + }; + + const offsetResults = + 884 + + 36 * prolog.nodeCount + + 52 * prolog.linkCount + + 8 * prolog.resAndTankCount + + 28 * prolog.pumpCount + + 4; + + const nodes: NodeResults[] = [...Array(prolog.nodeCount)].map((_, i) => { + return getNodeResults(prolog, offsetResults, i, view1); + }); + const links: LinkResults[] = [...Array(prolog.linkCount)].map((_, i) => { + return getLinkResults(prolog, offsetResults, i, view1); + }); + + const data: EpanetResults = { + prolog, + results: { + nodes, + links, + }, + }; + return data; +} + +const getNodeResults = ( + prolog: EpanetProlog, + offsetResults: number, + nodeIndex: number, + dataView: DataView +): NodeResults => { + const nodeResults = { + demand: [], + head: [], + pressure: [], + waterQuality: [], + }; + + const result: NodeResults = [ + 'demand', + 'head', + 'pressure', + 'waterQuality', + ].reduce((map, obj, i) => { + return { + ...map, + [obj]: getResultByteOffSet( + prolog, + offsetResults, + true, + nodeIndex, + i + ).map(x => dataView.getFloat32(x, true)), + }; + }, nodeResults); + + return result; +}; + +const getLinkResults = ( + prolog: EpanetProlog, + offsetResults: number, + linkIndex: number, + dataView: DataView +): LinkResults => { + const linkResults = { + flow: [], + velcoity: [], + headloss: [], + avgWaterQuality: [], + status: [], + setting: [], + reactionRate: [], + friction: [], + }; + + const result: LinkResults = [ + 'flow', + 'velcoity', + 'headloss', + 'avgWaterQuality', + 'status', + 'setting', + 'reactionRate', + 'friction', + ].reduce((map, obj, i) => { + return { + ...map, + [obj]: getResultByteOffSet( + prolog, + offsetResults, + false, + linkIndex, + i + ).map(x => dataView.getFloat32(x, true)), + }; + }, linkResults); + + return result; +}; + +const getResultByteOffSet = ( + prolog: EpanetProlog, + offsetResults: number, + isNode: boolean, + objIndex: number, + resultType: NodeResultTypes | LinkResultTypes +): number[] => { + const linkResultOffset = isNode ? 0 : 16 * prolog.nodeCount; + const typeCount = isNode ? prolog.nodeCount : prolog.linkCount; + const resultSize = 16 * prolog.nodeCount + 32 * prolog.linkCount; + const answer = [...Array(prolog.reportingPeriods)].map( + (_, i) => + offsetResults + + resultSize * i + + linkResultOffset + + 4 * objIndex + + 4 * resultType * typeCount + ); + return answer; +}; diff --git a/packages/epanet-js/src/index.ts b/packages/epanet-js/src/index.ts index 41000e2..7e9bbca 100644 --- a/packages/epanet-js/src/index.ts +++ b/packages/epanet-js/src/index.ts @@ -1,3 +1,4 @@ export { default as Workspace } from './Workspace/Workspace'; export { default as Project } from './Project/Project'; export * from './enum/index'; +export * from './OutputReader/index';