UNPKG

ccs-sim

Version:
303 lines (302 loc) 13.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const fs_1 = __importDefault(require("fs")); const yaml_1 = __importDefault(require("yaml")); const snapshotBuilder_1 = __importDefault(require("./snapshotBuilder")); const OLGA = { parse: (fileString) => { const lines = fileString.split('\n'); const linesReversed = lines.slice().reverse(); const lineThatStartsWith = (word, backwards = false) => { const searchArr = backwards ? linesReversed : lines; const idx = searchArr.findIndex((line) => line.startsWith(word.toUpperCase())); if (idx < 0) { throw new Error(`Line not found: ${word}`); } if (backwards) { return [lines.length - idx - 1, linesReversed[idx]]; } return [idx, lines[idx]]; }; const lastLineThatStartsWith = (word) => { return lineThatStartsWith(word, true); }; const keyLines = { initialConditions: lineThatStartsWith('initialconditions'), geometry: lineThatStartsWith('geometry'), firstPipe: lineThatStartsWith('pipe'), lastPipe: lastLineThatStartsWith('pipe'), }; const readLineProperties = (line) => { if (typeof line !== 'string') { line = line[1]; } line = line.replace(/NSEGMENT=\d+,\s/g, ''); line = line.replace(/LSEGMENT=.+\).+?\s/g, ''); const [type, parameterStrings] = [ line.substring(0, line.indexOf(' ')), line.substring(line.indexOf(' ')).trim().split(', '), ]; const unitConversion = (valueString) => { const matchName = valueString.match(/".+?"/); if (matchName) { return [matchName[0].substring(1, matchName[0].length - 1), '-']; } const matchNum = valueString.match(/-?[0-9]+\.?[0-9]*/); if (matchNum) { const numVal = matchNum[0]; let num = Number(numVal); let unitString = valueString.substring(numVal.length).trim(); switch (unitString) { case 'km': num = num * 1000; unitString = 'm'; break; case 'mm': num = num / 1000; unitString = 'm'; break; } return [Number(num.toFixed(4)), unitString]; } return [null, null]; }; const parameters = parameterStrings.reduce((acc, param) => { const [property, valueString] = param .split('=') .map((s) => s.trim()); const converted = unitConversion(valueString); if (converted[0] || converted[1]) { acc[property] = converted; } return acc; }, type === 'GEOMETRY' ? { YSTART: [0, 'm'] } : {}); return { type, parameters }; }; const INLET = readLineProperties(keyLines.geometry); let prevX = 0; const getXLength = (lineParams) => { if (!lineParams.XEND) return 0; const length = lineParams.XEND[0] - prevX; prevX = lineParams.XEND[0]; return length; }; const getYGain = (lineParams) => { const elevation = endElevation; if (lineParams.YEND) { endElevation = lineParams.YEND; } return elevation[0]; }; let endElevation = INLET.parameters.YSTART; const transformProperties = (lineProps) => { const params = lineProps.parameters; const instructionMap = { GEOMETRY: 'inlet', PIPE: 'pipeseg', }; const instructionType = instructionMap[lineProps.type]; const x = getXLength(params); const y = getYGain(params); const length = instructionType === instructionMap.GEOMETRY ? 0 : Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); const transformed = { [instructionType]: { name: params.LABEL[0], length, elevation: y, diameters: params.DIAMETER ? [params.DIAMETER[0]] : undefined, }, }; for (const key of Object.keys(transformed[instructionType])) { if (!transformed[instructionType][key] && key !== 'elevation') { delete transformed[instructionType][key]; } } const maxSegLength = 200; const reduceToMaxLengthArr = (len) => { if (len < maxSegLength) return [len]; const lengths = []; const sum = () => lengths.reduce((acc, a) => acc + a, 0); const remainder = () => len - sum(); while (remainder() >= maxSegLength) { lengths.push(maxSegLength); } if (remainder()) { lengths.push(remainder()); } else return [maxSegLength]; return lengths; }; if (instructionType === 'pipeseg' && transformed.pipeseg.length && transformed.pipeseg.length > maxSegLength) { const fullLength = transformed.pipeseg.length; const seriesLengths = reduceToMaxLengthArr(fullLength); // Elevation let lengthSoFar = 0; const startElevation = transformed.pipeseg .elevation; const elevationIncrease = endElevation[0] - startElevation; const elevations = seriesLengths.map((sLength) => { const cos = x / length; lengthSoFar += cos * sLength; const yGain = (elevationIncrease * lengthSoFar) / fullLength; return Number((startElevation + yGain).toFixed(4)); }); elevations.unshift(startElevation); elevations.pop(); transformed.pipeseries = { n: seriesLengths.length, pipeDef: { name: transformed.pipeseg.name, length: fullLength, elevation: startElevation, diameters: [ ...transformed.pipeseg.diameters, ], }, elevations, lengths: seriesLengths, }; delete transformed.pipeseg; } return transformed; }; const pipes = lines .slice(keyLines.firstPipe[0], keyLines.lastPipe[0] + 1) .map(readLineProperties); const data = { instructions: [ transformProperties(INLET), ...pipes.map(transformProperties), ], }; return data; }, }; class Parser { constructor() { this.keyPoints = []; // do nothing } readFile(fileName, save = false) { const file = fs_1.default.readFileSync(fileName, 'utf-8'); if (!file) { throw new Error(`No file: ${fileName}`); } const fileExtension = fileName.split('.').pop(); switch (fileExtension) { case 'yml': case 'yaml': this.data = yaml_1.default.parse(file); break; case 'genkey': this.data = OLGA.parse(file); break; default: throw new Error(`File type not supported: ${fileExtension}`); } if (save) { fs_1.default.writeFileSync(`${fileName.substring(0, fileName.indexOf('.'))}.yml`, yaml_1.default.stringify(this.data)); } return this.data; } build() { return __awaiter(this, void 0, void 0, function* () { if (!this.data) { throw new Error(`No data - call this.readFile(fileName) before this.build()`); } let builder = new snapshotBuilder_1.default(); for (const instruction of this.data.instructions) { for (let [type, parameters] of Object.entries(instruction)) { type = type.toLowerCase(); if (['selectsplitter', 'branch', 'setfluid'].includes(type)) { switch (type) { case 'selectsplitter': const { id } = parameters; builder.selectSplitter(id); break; case 'branch': const pipeDef = parameters; builder = builder.branch(pipeDef); break; case 'setfluid': const { pressure, temperature, flowrate } = parameters; yield builder.setFluid(pressure, temperature, flowrate); break; } continue; } switch (type) { case 'inlet': { const { name, physical } = parameters; builder = builder.addInlet(name, physical); } break; case 'pipeseg': { const pipeDef = parameters; builder = builder.chainAddPipeSeg(pipeDef); } break; case 'splitter': { const { name, physical } = parameters; builder = builder.addSplitter(name, physical); } break; case 'well': { const { name, physical, realReservoirName } = parameters; builder = builder.addWell(name, physical, realReservoirName); } break; case 'reservoir': { const { name, physical, pressure } = parameters; builder = builder.addReservoir(name, physical, pressure); } break; case 'pipeseries': { const { n, pipeDef, elevations, lengths } = parameters; builder = builder.addPipeSeries(n, pipeDef, elevations, lengths); } break; case 'valve': { const { name, physical, inputPressure } = parameters; builder = builder.addValve(name, physical, inputPressure); } break; default: throw new Error(`${type} not supported`); } } } this.keyPoints = builder.keyPoints; this.fluid = builder.fluid; return builder.elements[0]; }); } } exports.default = Parser;