'use strict'; const { BaseNodeAdapter } = require('generalFunctions'); const Reactor = require('./specificClass.js'); const commands = require('./commands'); const SPECIES = ['S_O','S_I','S_S','S_NH','S_N2','S_NO','S_HCO', 'X_I','X_S','X_H','X_STO','X_A','X_TS']; class nodeClass extends BaseNodeAdapter { static DomainClass = Reactor; static commands = commands; // Tick-driven: ASM kinetics integrate over wall-clock time. The engine's // updateState computes how many internal Euler/FD steps fit in the elapsed // ms; without a periodic tick the integrator never advances. static tickInterval = 1000; static statusInterval = 1000; buildDomainConfig(uiConfig) { const initialState = {}; for (const k of SPECIES) initialState[k] = parseFloat(uiConfig[`${k}_init`]); return { reactor: { reactor_type: uiConfig.reactor_type, volume: parseFloat(uiConfig.volume), length: parseFloat(uiConfig.length), resolution_L: parseInt(uiConfig.resolution_L, 10), alpha: parseFloat(uiConfig.alpha), n_inlets: parseInt(uiConfig.n_inlets, 10), kla: parseFloat(uiConfig.kla), timeStep: parseFloat(uiConfig.timeStep), speedUpFactor: Number(uiConfig.speedUpFactor) || 1, }, initialState, }; } // The kinetics engine drives Port-0 effluent + grid-profile shapes that // don't fit BaseNodeAdapter's delta-compressed payload. Override the // periodic emission so the Fluent / GridProfile contract is preserved. _emitOutputs() { const src = this.source; if (!src?.engine) return; src.updateState(Date.now()); const grid = src.getGridProfile; if (grid) this.node.send([{ topic: 'GridProfile', payload: grid }, null, null]); const raw = src.getOutput(); const influx = this._output.formatMsg(raw, src.config || this.config, 'influxdb'); this.node.send([src.getEffluent, influx, null]); } } module.exports = nodeClass;