MEASUR-Tools-Suite v1.2.4
The MEASUR Tools Suite is a collection of industrial efficiency calculations written in C++ and with bindings for compilation to WebAssembly.
Loading...
Searching...
No Matches
process_cooling.h
1#pragma once
2
22#include <algorithm>
23#include <cmath>
24#include <stdexcept>
25#include <string>
26#include <utility>
27#include <vector>
28
29using namespace std;
30
31constexpr int MONTHS = 12;
32constexpr int LOAD_NUM = 11;
33constexpr int HOURS_IN_YEAR = 8760;
34constexpr int CHILLER_COEFFS_CNT = 7; // 7 columns for each chiller, polynomial to either 3rd (for FullLoadEffKnown or custom chiller) or 5th degree
35
49 public:
50 enum RefrigerantType { R_11, R_123, R_12, R_134a, R_22, R_717 };
51
52 enum ACSourceLocation { Inside, Outside };
53
54 enum CoolingSystemType { Water, Air };
55
56 enum CellFanType { AxialFan, CentrifugalFan };
57
58 enum TowerSizedBy { Tonnage, Fan_HP, Unknown };
59
60 enum ChillerCompressorType { Centrifugal, Screw, Reciprocating };
61
62 enum FanMotorSpeedType { One, Two, Variable };
63
74 ChillerOutput(vector<vector<double>> efficiency, vector<vector<double>> hours, vector<vector<double>> power,
75 vector<vector<double>> energy)
76 : efficiency(std::move(efficiency)), hours(std::move(hours)), power(std::move(power)),
77 energy(std::move(energy)) {}
78
79 vector<vector<double>> efficiency;
80 vector<vector<double>> hours;
81 vector<vector<double>> power;
82 vector<vector<double>> energy;
83 };
84
92 explicit ChillerPumpingEnergyOutput(vector<double> pumpingEnergy)
93 : chillerPumpingEnergy(std::move(pumpingEnergy)) {}
94
95 vector<double> chillerPumpingEnergy;
96 };
97
98 struct TowerOutput {
103 TowerOutput() = default;
104
112 TowerOutput(vector<double> hours, vector<double> energy) : hours(std::move(hours)), energy(std::move(energy)) {}
113
114 vector<double> tempBins = {35, 45, 55, 65, 75, 75};
115 vector<double> hours;
116 vector<double> energy;
117 };
118
125
137 WaterCooledSystemInput(double CHWT, bool useFreeCooling, double HEXApproachTemp, bool constantCWT, double CWT,
138 bool CWVariableFlow, double CWFlowRate, double CWTFollow)
139 : CHWT(CHWT), useFreeCooling(useFreeCooling), HEXApproachTemp(HEXApproachTemp), constantCWT(constantCWT),
140 CWT(CWT), CWVariableFlow(CWVariableFlow), CWFlowRate(CWFlowRate), CWTFollow(CWTFollow) {
141 isWaterCooled = true;
142 }
143
144 double CHWT = 44;
145 bool useFreeCooling = false;
146 double HEXApproachTemp = 0;
147 bool constantCWT = true;
148 double CWT = 85;
149 bool CWVariableFlow = true;
150 double CWFlowRate = 3;
151 double CWTFollow = 0;
152 bool isWaterCooled = false;
153 };
154
161
170 AirCooledSystemInput(double CHWT, double OADT, ACSourceLocation ACSource, double indoorTemp, double CWTFollow)
171 : CHWT(CHWT), OADT(OADT), ACSource(ACSource), indoorTemp(indoorTemp), CWTFollow(CWTFollow) {
172 isAirCooled = true;
173 }
174
175 double CHWT = 44;
176 double OADT = 95;
177 ACSourceLocation ACSource = ACSourceLocation::Outside;
178 double indoorTemp = 75;
179 double CWTFollow = 0;
180 bool isAirCooled = false;
181 };
182
183 struct PumpInput {
192 PumpInput(bool variableFlow, double flowRate, double efficiency, double motorSize, double motorEfficiency)
193 : variableFlow(variableFlow), flowRate(flowRate), efficiency(efficiency * 100), motorSize(motorSize),
194 motorEfficiency(motorEfficiency * 100) {}
195
196 bool variableFlow;
197 double flowRate;
198 double efficiency;
199 double motorSize;
200 double motorEfficiency;
201 };
202
203 struct TowerInput {
208 TowerInput() = default;
209
223 TowerInput(int numTower, int numFanPerTower_Cells, FanMotorSpeedType fanSpeedType, TowerSizedBy towerSizing,
224 CellFanType towerCellFanType, double cellFanHP, double tonnage)
225 : numTower(numTower), numFanPerTower_Cells(numFanPerTower_Cells), fanSpeedType(fanSpeedType), towerSizing(towerSizing),
226 towerCellFanType(towerCellFanType), fanHP(cellFanHP), tonnage(tonnage) {}
227
228 int numTower;
229 int numFanPerTower_Cells;
230 FanMotorSpeedType fanSpeedType;
231 TowerSizedBy towerSizing;
232 CellFanType towerCellFanType;
233 double fanHP;
234 double tonnage;
235 };
236
253 ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff,
254 double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector<vector<double>> monthlyLoads)
255 : chillerType(chillerType), capacity(capacity), isFullLoadEffKnown(isFullLoadEffKnown),
256 fullLoadEff(fullLoadEff), age(age), installVSD(installVSD),
257 useARIMonthlyLoadSchedule(useARIMonthlyLoadSchedule), monthlyLoads(std::move(monthlyLoads)),
258 isCustomChiller(false), loadAtPercent({}), kwPerTonLoads({}), changeRefrig(false),
259 currentRefrig(RefrigerantType::R_11), proposedRefrig(RefrigerantType::R_11) {
260 InitNonVaryingMonthlyLoad();
261 }
262
282 ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff,
283 double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector<vector<double>> monthlyLoads,
284 bool changeRefrig, RefrigerantType currentRefrig, RefrigerantType proposedRefrig)
285 : chillerType(chillerType), capacity(capacity), isFullLoadEffKnown(isFullLoadEffKnown),
286 fullLoadEff(fullLoadEff), age(age), installVSD(installVSD),
287 useARIMonthlyLoadSchedule(useARIMonthlyLoadSchedule), monthlyLoads(std::move(monthlyLoads)),
288 isCustomChiller(false), loadAtPercent({}), kwPerTonLoads({}), changeRefrig(changeRefrig),
289 currentRefrig(currentRefrig), proposedRefrig(proposedRefrig) {
290 InitNonVaryingMonthlyLoad();
291 }
292
311 ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff,
312 double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector<vector<double>> monthlyLoads,
313 RefrigerantType currentRefrig, RefrigerantType proposedRefrig)
314 : chillerType(chillerType), capacity(capacity), isFullLoadEffKnown(isFullLoadEffKnown),
315 fullLoadEff(fullLoadEff), age(age), installVSD(installVSD),
316 useARIMonthlyLoadSchedule(useARIMonthlyLoadSchedule), monthlyLoads(std::move(monthlyLoads)),
317 isCustomChiller(false), loadAtPercent({}), kwPerTonLoads({}), changeRefrig(true),
318 currentRefrig(currentRefrig), proposedRefrig(proposedRefrig) {
319 InitNonVaryingMonthlyLoad();
320 }
321
340 ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff,
341 double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector<vector<double>> monthlyLoads,
342 vector<double> loadAtPercent, vector<double> kwPerTonLoads)
343 : chillerType(chillerType), capacity(capacity), isFullLoadEffKnown(isFullLoadEffKnown),
344 fullLoadEff(fullLoadEff), age(age), installVSD(installVSD),
345 useARIMonthlyLoadSchedule(useARIMonthlyLoadSchedule), monthlyLoads(std::move(monthlyLoads)),
346 isCustomChiller(true), loadAtPercent(std::move(loadAtPercent)), kwPerTonLoads(std::move(kwPerTonLoads)),
347 changeRefrig(false), currentRefrig(RefrigerantType::R_11), proposedRefrig(RefrigerantType::R_11) {
348 InitNonVaryingMonthlyLoad();
349 SetCustomCoefficient();
350 }
351
373 ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff,
374 double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector<vector<double>> monthlyLoads,
375 vector<double> loadAtPercent, vector<double> kwPerTonLoads, RefrigerantType currentRefrig,
376 RefrigerantType proposedRefrig)
377 : chillerType(chillerType), capacity(capacity), isFullLoadEffKnown(isFullLoadEffKnown),
378 fullLoadEff(fullLoadEff), age(age), installVSD(installVSD),
379 useARIMonthlyLoadSchedule(useARIMonthlyLoadSchedule), monthlyLoads(std::move(monthlyLoads)),
380 isCustomChiller(true), loadAtPercent(std::move(loadAtPercent)), kwPerTonLoads(std::move(kwPerTonLoads)),
381 changeRefrig(true), currentRefrig(currentRefrig), proposedRefrig(proposedRefrig) {
382 InitNonVaryingMonthlyLoad();
383 SetCustomCoefficient();
384 }
385
386 ChillerCompressorType chillerType;
387 double capacity;
388 bool isFullLoadEffKnown;
389 double fullLoadEff;
390 double age;
391 bool installVSD;
392 bool useARIMonthlyLoadSchedule;
393 vector<vector<double>> monthlyLoads;
394
395 bool isCustomChiller;
396 vector<double> loadAtPercent;
397 vector<double> kwPerTonLoads;
398
399 bool changeRefrig = false;
400 RefrigerantType currentRefrig;
401 RefrigerantType proposedRefrig;
402
403 vector<double> customCoeffs;
404 vector<double> customCoeffs_eff;
405
406 private:
407 void InitNonVaryingMonthlyLoad() {
408 if (monthlyLoads.size() == 1) {
409 auto monthlyLoad = monthlyLoads[0];
410
411 for (int i = 0; i < 11; i++) {
412 monthlyLoads.push_back(monthlyLoad);
413 }
414 }
415 }
416
417 void SetCustomCoefficient() {
418 if (loadAtPercent.empty() || kwPerTonLoads.empty() || loadAtPercent.size() != kwPerTonLoads.size()) {
419 throw std::runtime_error("Invalid input provided for loadAtPercent or kwPerTonLoads, should be non empty and have same number of elements.");
420 }
421
422 auto size = static_cast<int>(loadAtPercent.size());
423
424 // % loading in ascending order (25, 50, 75, 100)
425 if (loadAtPercent[0] > loadAtPercent[size-1]) {
426 std::reverse(loadAtPercent.begin(), loadAtPercent.end());
427 std::reverse(kwPerTonLoads.begin(), kwPerTonLoads.end());
428 }
429
430 vector<double> x(size, 0);
431 vector<double> y(size, 0);
432 const auto kwPerTonLoadAtMaxLoad = kwPerTonLoads[size-1];
433
434 if (kwPerTonLoadAtMaxLoad == 0) {
435 throw std::runtime_error("% loading @ 100 % cannot be zero.");
436 }
437
438 for (int i = 0; i < size; i++) {
439 x[i] = loadAtPercent[i]/100.0;
440 y[i] = kwPerTonLoads[i] * x[i] / kwPerTonLoadAtMaxLoad;
441 }
442 vector<double> coeff = solveForCoefficients(x, y);
443 vector<double> coeff_eff = solveForCoefficients(x, kwPerTonLoads);
444
445 size = static_cast<int>(coeff.size());
446 customCoeffs.resize(size, 0);
447 customCoeffs_eff.resize(size, 0);
448 for (int i = 0; i < size; i++) {
449 customCoeffs[i] = coeff[i];
450 customCoeffs_eff[i] = coeff_eff[i];
451 }
452 }
453
454 static vector<double> solveForCoefficients(const vector<double>& x, vector<double> y) {
455 if (x.empty() || x.size() != y.size())
456 return {};
457
458 const int n = static_cast<int>(x.size());
459
460 vector<vector<double>> a(n, vector<double>(n, 0));
461 for (int i = 0; i < n; ++i) {
462 for (int j = 0; j < n; ++j) {
463 a[i][j] = pow(x[i], n - 1 - j);
464 }
465 }
466
467 // Forward Elimination
468 for (int k = 0; k < n - 1; ++k) {
469 for (int i = k + 1; i < n; ++i) {
470 double factor = a[i][k] / a[k][k];
471 for (int j = k + 1; j < n; ++j) {
472 a[i][j] -= factor * a[k][j];
473 }
474 y[i] -= factor * y[k];
475 }
476 }
477
478 // Back Substitution
479 vector<double> coeff(n, 0);
480 coeff[n - 1] = y[n - 1] / a[n - 1][n - 1];
481 for (int i = n - 2; i >= 0; --i) {
482 double sum = y[i];
483 for (int j = i + 1; j < n; ++j) {
484 sum -= a[i][j] * coeff[j];
485 }
486 coeff[i] = sum / a[i][i];
487 }
488
489 return coeff;
490 }
491 };
492
493 ~ProcessCooling() = default;
494
509 ProcessCooling(const vector<int>& systemOperationAnnualHours, const vector<double>& weatherDryBulbHourlyTemp,
510 const vector<double>& weatherWetBulbHourlyTemp, const vector<ChillerInput>& chillerInputList,
511 const TowerInput& towerInput, const WaterCooledSystemInput& waterCooledSystemInput)
512 : ProcessCooling(systemOperationAnnualHours, weatherDryBulbHourlyTemp, weatherWetBulbHourlyTemp,
513 chillerInputList, {}, towerInput, waterCooledSystemInput) {}
514
526 ProcessCooling(const vector<int>& systemOperationAnnualHours, const vector<double>& weatherDryBulbHourlyTemp,
527 const vector<double>& weatherWetBulbHourlyTemp, const vector<ChillerInput>& chillerInputList,
528 const AirCooledSystemInput& airCooledSystemInput)
529 : ProcessCooling(systemOperationAnnualHours, weatherDryBulbHourlyTemp, weatherWetBulbHourlyTemp,
530 chillerInputList, airCooledSystemInput, {}, {}) {}
531
537
543
550
562 static vector<int> getSysOpAnnualHours(const vector<int>& weeklyOpStartHour, const vector<int>& weeklyOpStopHour, const vector<int>& monthlyOpMaxHour);
563
572 vector<double> getChillerEfficiencyCoeffs(int chillerIndex) const;
573
584 vector<double> getChillerARIEnergyEfficiency(int chillerIndex, const vector<double>& loadAtPercent, bool applyFactoring) const;
585
586 private:
587 ProcessCooling(const vector<int>& systemOperationAnnualHours, const vector<double>& weatherDryBulbHourlyTemp,
588 const vector<double>& weatherWetBulbHourlyTemp, const vector<ChillerInput>& chillerInputList,
589 const AirCooledSystemInput& airCooledSystemInput, const TowerInput& towerInput,
590 const WaterCooledSystemInput& waterCooledSystemInput);
591
592 vector<int> systemOperationAnnual;
593 vector<double> dryBulbHourlyTemp;
594 vector<double> wetBulbHourlyTemp;
595
596 TowerInput tower {};
597 WaterCooledSystemInput waterCooledSystem;
598 AirCooledSystemInput airCooledSystem;
599 CoolingSystemType coolingType;
600
601 double FCTemp = 0; // Free Cooling Temperature
602 vector<double> CWTHourly;
603
604 int numChillers;
605 vector<ChillerInput> chillers;
606 vector<vector<double>> chillerHourlyLoad;
607 vector<vector<double>> chillerHourlyLoadOperational;
608 vector<vector<double>> chillerEfficiencyCoeffs;
609 vector<vector<double>> chillerHourlyEfficiencyARI;
610 vector<vector<double>> chillerHourlyEfficiency;
611 vector<vector<double>> chillerHourlyPower;
612
613 int getChillerCapacityIndex(ChillerCompressorType chillerType, double capacity) const;
614
615 void annualChillerLoadProfile();
616
617 void annualChillerEfficiencyProfileARI();
618
619 void annualChillerEfficiencyProfile();
620
621 void annualChillerPowerProfile();
622
623 void setTowerFanHPTonnage();
624
625 double getChillerEffAtLoad(int c, double load, bool isFullLoadEffKnown, bool applyFactoring) const;
626
627 double getPercentFanPower(double wetBulbTemp, double percentWaterFlow, double range, double desiredApproach, int yearHourIndex);
628
629 double getPercentWaterFlow(int yearHourIndex) const;
630
631 double getRange(int yearHourIndex) const;
632
633 double getApproach(double wetBulbTemp) const;
634
635 double modifyPercentFanPower(double percentFanPower) const;
636
637 double getWeightedAverageChillerLoad(int yearHourIndex) const;
638
639 double getChillerTonnageTotal() const;
640
641 static double getCubeRoot(double number);
642
643 static double getPumpHP(double power);
644};
Calculator estimates energy consumption of operating Chillers, Pumps and Towers in a cooling system (...
TowerOutput calculateTowerEnergy()
ChillerOutput calculateChillerEnergy()
ProcessCooling(const vector< int > &systemOperationAnnualHours, const vector< double > &weatherDryBulbHourlyTemp, const vector< double > &weatherWetBulbHourlyTemp, const vector< ChillerInput > &chillerInputList, const TowerInput &towerInput, const WaterCooledSystemInput &waterCooledSystemInput)
ChillerPumpingEnergyOutput calculatePumpEnergy(PumpInput pump) const
ProcessCooling(const vector< int > &systemOperationAnnualHours, const vector< double > &weatherDryBulbHourlyTemp, const vector< double > &weatherWetBulbHourlyTemp, const vector< ChillerInput > &chillerInputList, const AirCooledSystemInput &airCooledSystemInput)
vector< double > getChillerEfficiencyCoeffs(int chillerIndex) const
static vector< int > getSysOpAnnualHours(const vector< int > &weeklyOpStartHour, const vector< int > &weeklyOpStopHour, const vector< int > &monthlyOpMaxHour)
vector< double > getChillerARIEnergyEfficiency(int chillerIndex, const vector< double > &loadAtPercent, bool applyFactoring) const
AirCooledSystemInput(double CHWT, double OADT, ACSourceLocation ACSource, double indoorTemp, double CWTFollow)
ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff, double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector< vector< double > > monthlyLoads, bool changeRefrig, RefrigerantType currentRefrig, RefrigerantType proposedRefrig)
ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff, double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector< vector< double > > monthlyLoads, RefrigerantType currentRefrig, RefrigerantType proposedRefrig)
ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff, double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector< vector< double > > monthlyLoads)
ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff, double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector< vector< double > > monthlyLoads, vector< double > loadAtPercent, vector< double > kwPerTonLoads)
ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff, double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector< vector< double > > monthlyLoads, vector< double > loadAtPercent, vector< double > kwPerTonLoads, RefrigerantType currentRefrig, RefrigerantType proposedRefrig)
ChillerOutput(vector< vector< double > > efficiency, vector< vector< double > > hours, vector< vector< double > > power, vector< vector< double > > energy)
ChillerPumpingEnergyOutput(vector< double > pumpingEnergy)
PumpInput(bool variableFlow, double flowRate, double efficiency, double motorSize, double motorEfficiency)
TowerInput(int numTower, int numFanPerTower_Cells, FanMotorSpeedType fanSpeedType, TowerSizedBy towerSizing, CellFanType towerCellFanType, double cellFanHP, double tonnage)
TowerOutput(vector< double > hours, vector< double > energy)
WaterCooledSystemInput(double CHWT, bool useFreeCooling, double HEXApproachTemp, bool constantCWT, double CWT, bool CWVariableFlow, double CWFlowRate, double CWTFollow)