|
|
|
|
@@ -30,6 +30,15 @@ class Diffuser extends BaseDomain {
|
|
|
|
|
this.i_flow = 0;
|
|
|
|
|
this.zoneVolume = _num(d.zoneVolume, 0);
|
|
|
|
|
|
|
|
|
|
// Membrane area per element. Curves declare it in _meta — that's the
|
|
|
|
|
// source of truth. Config can override (e.g. for a non-standard build).
|
|
|
|
|
// Final fallback 0.18 m² matches the Jäger TD-65 / GVA placeholder.
|
|
|
|
|
const curveArea = Number(this.specs?._meta?.membraneArea_m2_per_element);
|
|
|
|
|
const cfgArea = Number(d.membraneAreaPerElement);
|
|
|
|
|
this.i_membrane_area = Number.isFinite(cfgArea) && cfgArea > 0
|
|
|
|
|
? cfgArea
|
|
|
|
|
: (Number.isFinite(curveArea) && curveArea > 0 ? curveArea : 0.18);
|
|
|
|
|
|
|
|
|
|
this.n_kg = this._calcAirDensityMbar(1013.25, 0, 20);
|
|
|
|
|
this.n_flow = 0;
|
|
|
|
|
this.o_otr = 0;
|
|
|
|
|
@@ -39,6 +48,7 @@ class Diffuser extends BaseDomain {
|
|
|
|
|
this.o_kg = 0; this.o_kg_h = 0; this.o_kgo2_h = 0; this.o_kgo2 = 0;
|
|
|
|
|
this.o_kgo2_h_min = 0; this.o_kgo2_h_max = 0;
|
|
|
|
|
this.o_flow_element = 0;
|
|
|
|
|
this.o_flux_per_m2 = 0;
|
|
|
|
|
this.o_otr_min = 0; this.o_otr_max = 0;
|
|
|
|
|
this.o_p_min = 0; this.o_p_max = 0;
|
|
|
|
|
this.o_combined_eff = 0;
|
|
|
|
|
@@ -59,7 +69,8 @@ class Diffuser extends BaseDomain {
|
|
|
|
|
_recalculate() {
|
|
|
|
|
if (this.i_flow <= 0) {
|
|
|
|
|
this.idle = true;
|
|
|
|
|
this.n_flow = 0; this.o_otr = 0; this.o_p_flow = 0; this.o_flow_element = 0;
|
|
|
|
|
this.n_flow = 0; this.o_otr = 0; this.o_p_flow = 0;
|
|
|
|
|
this.o_flow_element = 0; this.o_flux_per_m2 = 0;
|
|
|
|
|
this.o_p_total = this.o_p_water;
|
|
|
|
|
this.o_kg = 0; this.o_kg_h = 0; this.o_kgo2_h = 0; this.o_kgo2 = 0;
|
|
|
|
|
this.o_combined_eff = 0; this.o_slope = 0;
|
|
|
|
|
@@ -147,9 +158,14 @@ class Diffuser extends BaseDomain {
|
|
|
|
|
this.o_kg_h = this.o_kg * flow;
|
|
|
|
|
this.n_flow = (this.o_kg / this.n_kg) * flow;
|
|
|
|
|
this.o_flow_element = Math.round((this.n_flow / this.i_n_elements) * 100) / 100;
|
|
|
|
|
// Specific flux through the membrane — the canonical x-axis of every
|
|
|
|
|
// curve file under datasets/assetData/curves/. Curves are indexed by
|
|
|
|
|
// bottom coverage % (this.i_diff_density) and queried at this flux.
|
|
|
|
|
const totalMembraneArea = this.i_n_elements * this.i_membrane_area;
|
|
|
|
|
this.o_flux_per_m2 = Math.round((this.n_flow / totalMembraneArea) * 100) / 100;
|
|
|
|
|
|
|
|
|
|
const otr = this._interpolateCurveByDensity(this.specs.otr_curve, this.i_diff_density, this.o_flow_element);
|
|
|
|
|
const pressure = this._interpolateCurveByDensity(this.specs.p_curve, 0, this.o_flow_element);
|
|
|
|
|
const otr = this._interpolateCurveByDensity(this.specs.otr_curve, this.i_diff_density, this.o_flux_per_m2);
|
|
|
|
|
const pressure = this._interpolateCurveByDensity(this.specs.p_curve, 0, this.o_flux_per_m2);
|
|
|
|
|
|
|
|
|
|
this.o_otr_min = otr.minY; this.o_otr_max = otr.maxY;
|
|
|
|
|
this.o_p_min = pressure.minY; this.o_p_max = pressure.maxY;
|
|
|
|
|
@@ -173,13 +189,15 @@ class Diffuser extends BaseDomain {
|
|
|
|
|
_checkLimits(minFlow, maxFlow) {
|
|
|
|
|
this.warning.text = []; this.warning.state = false;
|
|
|
|
|
this.alarm.text = []; this.alarm.state = false;
|
|
|
|
|
const f = this.o_flow_element;
|
|
|
|
|
// Compare against the canonical flux, since pressure.minX / maxX come
|
|
|
|
|
// from the per-m²-membrane curve.
|
|
|
|
|
const f = this.o_flux_per_m2;
|
|
|
|
|
for (const k of ['warning', 'alarm']) {
|
|
|
|
|
const band = this[k];
|
|
|
|
|
const lo = minFlow - minFlow * (band.flow.min.hyst / 100);
|
|
|
|
|
const hi = maxFlow + maxFlow * (band.flow.max.hyst / 100);
|
|
|
|
|
if (f < lo) { band.state = true; band.text.push(`${_cap(k)}: flow per element ${f} is below ${Math.round(lo * 100) / 100}`); }
|
|
|
|
|
if (f > hi) { band.state = true; band.text.push(`${_cap(k)}: flow per element ${f} exceeds ${Math.round(hi * 100) / 100}`); }
|
|
|
|
|
if (f < lo) { band.state = true; band.text.push(`${_cap(k)}: specific flux ${f} Nm³/(h·m²) is below ${Math.round(lo * 100) / 100}`); }
|
|
|
|
|
if (f > hi) { band.state = true; band.text.push(`${_cap(k)}: specific flux ${f} Nm³/(h·m²) exceeds ${Math.round(hi * 100) / 100}`); }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -209,6 +227,7 @@ class Diffuser extends BaseDomain {
|
|
|
|
|
oPLoss: this.o_p_total,
|
|
|
|
|
oKgo2H: this.o_kgo2_h,
|
|
|
|
|
oFlowElement: this.o_flow_element,
|
|
|
|
|
oFluxPerM2: this.o_flux_per_m2,
|
|
|
|
|
efficiency: this.o_combined_eff,
|
|
|
|
|
slope: this.o_slope,
|
|
|
|
|
oZoneOtr: this.getReactorOtr(this.zoneVolume),
|
|
|
|
|
@@ -240,6 +259,7 @@ class Diffuser extends BaseDomain {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
_meta: raw._meta || {},
|
|
|
|
|
supplier: raw._meta?.supplier || null,
|
|
|
|
|
type: raw._meta?.type || null,
|
|
|
|
|
model: raw._meta?.model || cfgModel,
|
|
|
|
|
|