11 #ifndef AMO_TOOLS_SUITE_FAN_H 12 #define AMO_TOOLS_SUITE_FAN_H 15 #include <unordered_map> 21 #include "FanShaftPower.h" 68 BaseGasDensity(
const double dryBulbTemp,
const double staticPressure,
const double barometricPressure,
69 const double gasDensity,
const GasType gasType)
70 : tdo(dryBulbTemp), pso(staticPressure), pbo(barometricPressure), gasDensity(gasDensity), gasType(gasType)
93 BaseGasDensity(
double const dryBulbTemp,
double const staticPressure,
double const barometricPressure,
94 double const relativeHumidityOrDewPoint,
GasType const gasType,
95 InputType const inputType,
double const specificGravity)
96 : tdo(dryBulbTemp), pso(staticPressure), pbo(barometricPressure), g(specificGravity), gasType(gasType)
98 saturationPressure = calculateSaturationPressure(tdo);
100 if (inputType == InputType::RelativeHumidity)
102 relativeHumidity = relativeHumidityOrDewPoint / 100;
104 else if (inputType == InputType::DewPoint)
106 relativeHumidity = calculateSaturationPressure(relativeHumidityOrDewPoint) / saturationPressure;
108 else if (inputType == InputType::WetBulbTemp)
110 throw std::runtime_error(
"The wrong constructor for BaseGasDensity was called here - check inputType field");
113 calculateFanAttributes(inputType, relativeHumidityOrDewPoint);
133 BaseGasDensity(
double const dryBulbTemp,
double const staticPressure,
double const barometricPressure,
134 double const wetBulbTemp,
GasType const gasType,
135 InputType const inputType,
double const specificGravity,
const double cpGas)
136 : tdo(dryBulbTemp), pso(staticPressure), pbo(barometricPressure), wetBulbTemp(wetBulbTemp), g(specificGravity), gasType(gasType)
138 if (inputType != InputType::WetBulbTemp)
139 throw std::runtime_error(
"The wrong constructor for BaseGasDensity was called - check inputType field");
140 saturationPressure = calculateSaturationPressure(tdo);
141 relativeHumidity = calculateRelativeHumidityFromWetBulb(tdo, wetBulbTemp, cpGas);
143 calculateFanAttributes(inputType);
164 double getGasDensity()
const 168 double getAbsolutePressureIn()
const 170 return absolutePressure;
172 double getSaturatedHumidityRatio()
const 174 return saturatedHumidity;
176 double getDegreeOfSaturation()
const 178 return saturationDegree;
180 double getHumidityRatio()
const 182 return humidityRatio;
184 double getSpecificVolume()
const 186 return specificVolume;
188 double getEnthalpy()
const 192 double getDewPoint()
const 196 double getRelativeHumidity()
const 198 return relativeHumidity;
200 double getSaturationPressure()
const 202 return saturationPressure;
204 double getWetBulbTemp()
const 218 double calculateWetBulbTemperature(
double dryBulbTemp,
double relativeHumidity,
double absolutePressure)
const 222 double humidityRatioNormal = calculateRatioRH(dryBulbTemp, relativeHumidity, absolutePressure, 1);
223 double wetBulbTemp = dryBulbTemp;
224 double humidityRatioNew = calculateHumidityRatioFromWetBulb(dryBulbTemp, wetBulbTemp, 0.24);
226 while (fabs((humidityRatioNew - humidityRatioNormal) / humidityRatioNormal) > 0.00001)
228 double humidityRatioNew2 = calculateHumidityRatioFromWetBulb(dryBulbTemp, wetBulbTemp - 0.001, 0.24);
229 double dw_dtwb = (humidityRatioNew - humidityRatioNew2) / 0.001;
230 wetBulbTemp = wetBulbTemp - (humidityRatioNew - humidityRatioNormal) / dw_dtwb;
231 humidityRatioNew = calculateHumidityRatioFromWetBulb(dryBulbTemp, wetBulbTemp, 0.24);
242 double calculateSaturationPressure(
double dryBulbTemp)
const 244 double const C1 = -5674.5359;
245 double const C2 = 6.3925247;
246 double const C3 = -0.009677843;
247 double const C4 = 0.00000062215701;
248 double const C5 = 2.0747825 * std::pow(10, -9);
249 double const C6 = -9.484024 * std::pow(10, -13);
250 double const C7 = 4.1635019;
251 double const C8 = -5800.2206;
252 double const C9 = 1.3914993;
253 double const C10 = -0.048640239;
254 double const C11 = 0.000041764768;
255 double const C12 = -0.000000014452093;
256 double const C13 = 6.5459673;
258 double const tKelvin = (dryBulbTemp + 459.67) * 0.555556;
260 if (tKelvin < 273.15)
262 double const p = std::exp(C1 / tKelvin + C2 + tKelvin * C3 + tKelvin * tKelvin * (C4 + tKelvin * (C5 + C6 * tKelvin)) + C7 * std::log(tKelvin));
263 return p * (29.9216 / 101325);
265 double const p = std::exp(C8 / tKelvin + C9 + tKelvin * (C10 + tKelvin * (C11 + tKelvin * C12)) + C13 * std::log(tKelvin));
267 return p * (29.9216 / 101325);
278 double calculateRatioRH(
const double dryBulbTemp,
const double relativeHumidity,
const double barometricPressure,
279 const double specificGravity)
const 281 auto const pw = (calculateSaturationPressure(dryBulbTemp) * relativeHumidity);
282 return (18.02 / (specificGravity * 28.98)) * pw / (barometricPressure - pw);
291 double calculateRelativeHumidityFromWetBulb(
const double dryBulbTemp,
const double wetBulbTemp,
292 const double cpGas)
const 294 double const nMol = 0.62198;
295 double const local_pIn = pbo + (pso / 13.608703);
297 double const psatDb = calculateSaturationPressure(dryBulbTemp);
299 double const psatWb = calculateSaturationPressure(wetBulbTemp);
300 double const wStar = nMol * psatWb / (local_pIn - psatWb);
301 double const w = ((1093 - (1 - 0.444) * wetBulbTemp) * wStar - cpGas * (dryBulbTemp - wetBulbTemp)) / (1093 + (0.444 * dryBulbTemp) - wetBulbTemp);
303 double const pV = local_pIn * w / (nMol + w);
327 double calculateHumidityRatioFromWetBulb(
const double dryBulbTemp,
const double wetBulbTemp,
const double cpGas)
const 329 double const nMol = 0.62198;
330 double const local_pIn = pbo + (pso / 13.608703);
332 double const psatWb = calculateSaturationPressure(wetBulbTemp);
333 double const wStar = nMol * psatWb / (local_pIn - psatWb);
334 double const w = ((1093 - (1 - 0.444) * wetBulbTemp) * wStar - cpGas * (dryBulbTemp - wetBulbTemp)) / (1093 + (0.444 * dryBulbTemp) - wetBulbTemp);
345 void calculateFanAttributes(
InputType const inputType,
double const relativeHumidityOrDewPoint = -1)
347 double const nMol = 0.62198;
349 absolutePressure = pbo + (pso / 13.608703);
350 saturatedHumidity = nMol * saturationPressure / (absolutePressure - saturationPressure);
351 saturationDegree = relativeHumidity / ( 1 + ( 1 - relativeHumidity) * saturatedHumidity / nMol);
352 humidityRatio = saturationDegree * saturatedHumidity;
353 specificVolume = (10.731557 * (tdo + 459.67) * (1 + 1.6078 * humidityRatio)) / (28.9645 * absolutePressure * 0.4911541);
354 gasDensity = (1 / specificVolume) * (1 + humidityRatio);
355 enthalpy = (0.247 * tdo) + (humidityRatio * (1061 + 0.444 * tdo));
357 if(inputType != InputType::DewPoint)
359 double const alpha = std::log(absolutePressure * 0.4911541 * humidityRatio / (nMol + humidityRatio));
363 dewPoint = 90.12 + 26.412 * alpha + 0.8927 * alpha * alpha;
367 dewPoint = 100.45 + 33.193 * alpha + 2.319 * alpha * alpha + 0.17074 * alpha * alpha * alpha + 1.2063 * (std::pow((absolutePressure * 0.4911541 * humidityRatio / (0.62196 + humidityRatio)), 0.1984));
373 dewPoint = relativeHumidityOrDewPoint;
376 if(inputType != InputType::WetBulbTemp)
378 wetBulbTemp = calculateWetBulbTemperature(tdo, relativeHumidity, absolutePressure);
383 const double tdo, pso, pbo;
390 double gasDensity, g;
405 double absolutePressure, saturatedHumidity, saturationDegree, humidityRatio, specificVolume, enthalpy, dewPoint, relativeHumidity, saturationPressure, wetBulbTemp;
431 Data(
const double density,
const double velocity,
const double volumeFlowRate,
const double velocityPressure,
432 const double totalPressure)
433 : gasDensity(density), gasVelocity(velocity), gasVolumeFlowRate(volumeFlowRate),
434 gasVelocityPressure(velocityPressure), gasTotalPressure(totalPressure) {}
436 const double gasDensity = 0, gasVelocity = 0, gasVolumeFlowRate = 0, gasVelocityPressure = 0, gasTotalPressure = 0;
446 struct DataFlange : Data
448 DataFlange(
const double density,
const double velocity,
const double volumeFlowRate,
const double velocityPressure,
449 const double totalPressure,
const double staticPressure)
450 : Data(density, velocity, volumeFlowRate, velocityPressure, totalPressure),
451 staticPressure(staticPressure) {}
453 const double staticPressure = 0;
457 explicit Output(
PlaneData const &planeData)
458 : fanInletFlange(getDataFlange(planeData.fanInletFlange)),
459 fanOrEvaseOutletFlange(getDataFlange(planeData.fanOrEvaseOutletFlange)),
460 flowTraverse(getData(planeData.flowTraverse)),
461 inletMstPlane(getData(planeData.inletMstPlane)),
462 outletMstPlane(getData(planeData.outletMstPlane)),
463 addlTravPlanes(getDataTrav(planeData.addlTravPlanes))
466 DataFlange fanInletFlange, fanOrEvaseOutletFlange;
467 Data flowTraverse, inletMstPlane, outletMstPlane;
468 std::vector<Data> addlTravPlanes;
472 planeData.calculate(baseGasDensity);
473 return Output(planeData);
477 static Data getData(
Planar const &plane)
479 return {plane.gasDensity, plane.gasVelocity, plane.gasVolumeFlowRate, plane.gasVelocityPressure, plane.gasTotalPressure};
481 static DataFlange getDataFlange(
Planar const &plane)
483 return {plane.gasDensity, plane.gasVelocity, plane.gasVolumeFlowRate, plane.gasVelocityPressure, plane.gasTotalPressure, plane.staticPressure};
485 static std::vector<Data> getDataTrav(std::vector<TraversePlane>
const &addlPlanes)
487 std::vector<Data> data;
488 for (
auto const &plane : addlPlanes)
490 data.push_back({plane.gasDensity, plane.gasVelocity, plane.gasVolumeFlowRate, plane.gasVelocityPressure, plane.gasTotalPressure});
497 TraversePlane flowTraverse, std::vector<TraversePlane> addlTravPlanes,
499 const double totalPressureLossBtwnPlanes1and4,
const double totalPressureLossBtwnPlanes2and5,
500 bool const plane5upstreamOfPlane2)
501 : fanInletFlange(std::move(fanInletFlange)), fanOrEvaseOutletFlange(std::move(fanOrEvaseOutletFlange)), flowTraverse(std::move(flowTraverse)),
502 addlTravPlanes(std::move(addlTravPlanes)), inletMstPlane(std::move(inletMstPlane)), outletMstPlane(std::move(outletMstPlane)),
503 plane5upstreamOfPlane2(plane5upstreamOfPlane2),
504 totalPressureLossBtwnPlanes1and4(totalPressureLossBtwnPlanes1and4),
505 totalPressureLossBtwnPlanes2and5(totalPressureLossBtwnPlanes2and5)
510 void establishFanInletOrOutletDensity(
Planar &plane,
511 std::function<
double(
Planar const &,
const double)>
const &calcDensity,
512 double const mTotal,
double const assumedDensity)
514 double calculatedDensity = assumedDensity;
515 for (
auto i = 0; i < 50; i++)
517 plane.gasDensity = calculatedDensity;
518 plane.gasVolumeFlowRate = mTotal / plane.gasDensity;
519 plane.gasVelocity = plane.gasVolumeFlowRate / plane.area;
520 plane.gasVelocityPressure = plane.gasDensity * std::pow(plane.gasVelocity / 1096, 2);
521 double fanInletOrOutletStaticPressure = plane.gasTotalPressure - plane.gasVelocityPressure;
522 double fanInletOrOutletGasDensity = calcDensity(plane, fanInletOrOutletStaticPressure);
524 calculatedDensity = fanInletOrOutletGasDensity;
525 if (fabs(fanInletOrOutletGasDensity - plane.gasDensity) < 0.0001)
527 plane.gasDensity = fanInletOrOutletGasDensity;
528 plane.staticPressure = fanInletOrOutletStaticPressure;
532 throw std::runtime_error(
"In PlaneData::establishFanInletOrOutletDensity - density iteration did not converge");
541 auto const calcDensity = [&bgd](
Planar const &plane,
const double psx) {
542 return bgd.gasDensity * (bgd.tdo + 460) * (psx + 13.63 * plane.barometricPressure) / ((plane.
dryBulbTemperature + 460) * (bgd.pso + 13.63 * bgd.pbo));
545 flowTraverse.gasDensity = calcDensity(flowTraverse, flowTraverse.staticPressure);
546 for (
auto &p : addlTravPlanes)
548 p.gasDensity = calcDensity(p, p.staticPressure);
550 inletMstPlane.gasDensity = calcDensity(inletMstPlane, inletMstPlane.staticPressure);
551 outletMstPlane.gasDensity = calcDensity(outletMstPlane, outletMstPlane.staticPressure);
553 flowTraverse.gasVelocity = 1096 * std::sqrt(flowTraverse.pv3 / flowTraverse.gasDensity);
554 flowTraverse.gasVolumeFlowRate = flowTraverse.gasVelocity * flowTraverse.area;
556 flowTraverse.gasVelocityPressure = flowTraverse.gasDensity * std::pow((flowTraverse.gasVelocity / 1096), 2);
557 flowTraverse.gasTotalPressure = flowTraverse.staticPressure + flowTraverse.gasVelocityPressure;
559 double mTotal = flowTraverse.gasDensity * flowTraverse.gasVolumeFlowRate;
560 for (
auto &plane : addlTravPlanes)
562 plane.gasVelocity = 1096 * std::sqrt(plane.pv3 / plane.gasDensity);
563 plane.gasVolumeFlowRate = plane.gasVelocity * plane.area;
565 plane.gasVelocityPressure = plane.gasDensity * std::pow((plane.gasVelocity / 1096), 2);
566 plane.gasTotalPressure = plane.staticPressure + plane.gasVelocityPressure;
567 mTotal += plane.gasDensity * plane.gasVolumeFlowRate;
570 inletMstPlane.gasVolumeFlowRate = mTotal / inletMstPlane.gasDensity;
571 inletMstPlane.gasVelocity = inletMstPlane.gasVolumeFlowRate / inletMstPlane.area;
572 inletMstPlane.gasVelocityPressure = inletMstPlane.gasDensity * std::pow((inletMstPlane.gasVelocity / 1096), 2);
573 inletMstPlane.gasTotalPressure = inletMstPlane.staticPressure + inletMstPlane.gasVelocityPressure;
576 fanInletFlange.gasTotalPressure = inletMstPlane.gasTotalPressure - totalPressureLossBtwnPlanes1and4;
579 establishFanInletOrOutletDensity(fanInletFlange, calcDensity, mTotal, inletMstPlane.gasDensity);
582 outletMstPlane.gasVolumeFlowRate = mTotal / outletMstPlane.gasDensity;
583 outletMstPlane.gasVelocity = outletMstPlane.gasVolumeFlowRate / outletMstPlane.area;
584 outletMstPlane.gasVelocityPressure = outletMstPlane.gasDensity * std::pow(outletMstPlane.gasVelocity / 1096, 2);
585 outletMstPlane.gasTotalPressure = outletMstPlane.staticPressure + outletMstPlane.gasVelocityPressure;
588 fanOrEvaseOutletFlange.gasTotalPressure = outletMstPlane.gasTotalPressure;
589 fanOrEvaseOutletFlange.gasTotalPressure +=
590 (plane5upstreamOfPlane2) ? -totalPressureLossBtwnPlanes2and5 : totalPressureLossBtwnPlanes2and5;
593 establishFanInletOrOutletDensity(fanOrEvaseOutletFlange, calcDensity, mTotal, outletMstPlane.gasDensity);
596 FlangePlane fanInletFlange, fanOrEvaseOutletFlange;
598 std::vector<TraversePlane> addlTravPlanes;
602 bool const plane5upstreamOfPlane2;
603 const double totalPressureLossBtwnPlanes1and4, totalPressureLossBtwnPlanes2and5;
606 friend struct NodeBinding;
618 : fanRatedInfo(fanRatedInfo), planeData(std::move(planeData)),
619 baseGasDensity(baseGasDensity), fanShaftPower(fanShaftPower)
621 this->planeData.calculate(this->baseGasDensity);
626 Results(
const double kpc,
const double power,
const double flow,
627 const double pressureTotal,
const double pressureStatic,
628 const double staticPressureRise)
629 : kpc(kpc), power(power),
630 flow(flow), pressureTotal(pressureTotal),
631 pressureStatic(pressureStatic), staticPressureRise(staticPressureRise)
634 const double kpc, power, flow, pressureTotal;
635 const double pressureStatic, staticPressureRise;
640 Output(
const double fanEfficiencyTotalPressure,
const double fanEfficiencyStaticPressure,
641 const double fanEfficiencyStaticPressureRise,
const Results asTested,
const Results converted)
642 : fanEfficiencyTotalPressure(fanEfficiencyTotalPressure), fanEfficiencyStaticPressure(fanEfficiencyStaticPressure),
643 fanEfficiencyStaticPressureRise(fanEfficiencyStaticPressureRise), asTested(asTested), converted(converted)
647 const double fanEfficiencyTotalPressure, fanEfficiencyStaticPressure, fanEfficiencyStaticPressureRise;
648 const Results asTested, converted;
654 double const x = (planeData.fanOrEvaseOutletFlange.gasTotalPressure - planeData.fanInletFlange.gasTotalPressure) / (planeData.fanInletFlange.gasTotalPressure + 13.63 * planeData.fanInletFlange.barometricPressure);
656 double isentropicExponent = 1.4;
657 if (baseGasDensity.gasType == BaseGasDensity::GasType::AIR)
658 isentropicExponent = 1.4;
661 double const z = ((isentropicExponent - 1) / isentropicExponent) * ((6362 * fanShaftPower.
getFanPowerInput() / planeData.fanInletFlange.gasVolumeFlowRate) / (planeData.fanInletFlange.gasTotalPressure + 13.63 * planeData.fanInletFlange.barometricPressure));
663 double const kp = (std::log(1 + x) / x) * (z / (std::log(1 + z)));
665 planeData.flowTraverse.gasTotalPressure =
666 planeData.flowTraverse.staticPressure + planeData.flowTraverse.gasVelocityPressure;
667 for (
auto &p : planeData.addlTravPlanes)
669 p.gasTotalPressure = p.staticPressure + p.gasVelocityPressure;
672 double const fanTotalPressure = planeData.fanOrEvaseOutletFlange.gasTotalPressure - planeData.fanInletFlange.gasTotalPressure + fanShaftPower.
getSEF();
674 double const fanStaticPressure = planeData.fanOrEvaseOutletFlange.staticPressure - planeData.fanInletFlange.gasTotalPressure + fanShaftPower.
getSEF();
676 double const staticPressureRise =
677 planeData.fanOrEvaseOutletFlange.staticPressure - planeData.fanInletFlange.staticPressure +
680 double const kpFactorRatio = calculateCompressibilityFactor(x, z, isentropicExponent);
683 double const qc = planeData.fanInletFlange.gasVolumeFlowRate * (fanRatedInfo.fanSpeedCorrected / fanRatedInfo.fanSpeed) * kpFactorRatio;
685 double const ptc = fanTotalPressure * kpFactorRatio * std::pow(fanRatedInfo.fanSpeedCorrected / fanRatedInfo.fanSpeed, 2) * (fanRatedInfo.densityCorrected / planeData.fanInletFlange.gasDensity);
687 double const psc = fanStaticPressure * kpFactorRatio * std::pow(fanRatedInfo.fanSpeedCorrected / fanRatedInfo.fanSpeed, 2) * (fanRatedInfo.densityCorrected / planeData.fanInletFlange.gasDensity);
690 staticPressureRise * kpFactorRatio * std::pow(fanRatedInfo.fanSpeedCorrected / fanRatedInfo.fanSpeed, 2) * (fanRatedInfo.densityCorrected / planeData.fanInletFlange.gasDensity);
692 double const hc = fanShaftPower.
getFanPowerInput() * kpFactorRatio * std::pow(fanRatedInfo.fanSpeedCorrected / fanRatedInfo.fanSpeed, 3) * (fanRatedInfo.densityCorrected / planeData.fanInletFlange.gasDensity);
694 double const kpc = kp / kpFactorRatio;
696 double const efficiency = planeData.fanInletFlange.gasVolumeFlowRate * kp / (6362 * fanShaftPower.
getFanPowerInput());
699 fanTotalPressure * efficiency * 100, fanStaticPressure * efficiency * 100, staticPressureRise * efficiency * 100, {kpFactorRatio, fanShaftPower.
getFanPowerInput(), planeData.fanInletFlange.gasVolumeFlowRate, fanTotalPressure, fanStaticPressure, staticPressureRise}, {kpc, hc, qc, ptc, psc, sprc}};
703 double calculateCompressibilityFactor(
const double x,
const double z,
const double isentropic)
705 double assumedKpOverKpc = 1.0;
706 auto const &p1 = planeData.fanInletFlange;
707 for (
auto i = 0; i < 50; i++)
709 double const pt1c = p1.gasTotalPressure * std::pow(fanRatedInfo.fanSpeedCorrected / fanRatedInfo.fanSpeed, 2) * (fanRatedInfo.densityCorrected / p1.gasDensity) * assumedKpOverKpc;
712 double const zOverZc = ((pt1c + 13.63 * fanRatedInfo.pressureBarometricCorrected) / (p1.gasTotalPressure + 13.63 * p1.barometricPressure)) * (p1.gasDensity / fanRatedInfo.densityCorrected) * std::pow(fanRatedInfo.fanSpeed / fanRatedInfo.fanSpeedCorrected, 2) * ((isentropic - 1) / isentropic) * (isentropic / (isentropic - 1));
714 double const zc = z / zOverZc;
716 double const ln1xc = std::log(1 + x) * ((std::log(1 + zc) / std::log(1 + z))) * ((isentropic - 1) / isentropic) * (isentropic / (isentropic - 1));
718 double const xc = std::exp(ln1xc) - 1;
720 double const kpOverKpc = (z / zc) * (xc / x) * (isentropic / (isentropic - 1)) * ((isentropic - 1) / isentropic);
721 if (fabs(kpOverKpc - assumedKpOverKpc) < 0.0000001)
725 assumedKpOverKpc = kpOverKpc;
727 throw std::runtime_error(
"compressibility factor ratio iteration did not converge");
736 #endif //AMO_TOOLS_SUITE_FAN_H
BaseGasDensity(double const dryBulbTemp, double const staticPressure, double const barometricPressure, double const relativeHumidityOrDewPoint, GasType const gasType, InputType const inputType, double const specificGravity)
const double dryBulbTemperature
BaseGasDensity(const double dryBulbTemp, const double staticPressure, const double barometricPressure, const double gasDensity, const GasType gasType)
double getFanPowerInput() const