MEASUR-Tools-Suite v1.0.11
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 <fstream>
25#include <stdexcept>
26#include <string>
27#include <utility>
28#include <vector>
29
30using namespace std;
31
32constexpr int MONTHS = 12;
33constexpr int LOAD_NUM = 11;
34constexpr int HOURS_IN_YEAR = 8760;
35constexpr int CHILLER_COEFFS_CNT = 7; // 7 columns for each chiller, polynomial to either 3rd (for FullLoadEffKnown or custom chiller) or 5th degree
36
50 public:
51 enum RefrigerantType { R_11, R_123, R_12, R_134a, R_22, R_717 };
52
53 enum ACSourceLocation { Inside, Outside };
54
55 enum CoolingSystemType { Water, Air };
56
57 enum CellFanType { AxialFan, CentrifugalFan };
58
59 enum TowerSizedBy { Tonnage, Fan_HP, Unknown };
60
61 enum ChillerCompressorType { Centrifugal, Screw, Reciprocating };
62
63 enum FanMotorSpeedType { One, Two, Variable };
64
75 ChillerOutput(vector<vector<double>> efficiency, vector<vector<double>> hours, vector<vector<double>> power,
76 vector<vector<double>> energy)
77 : efficiency(std::move(efficiency)), hours(std::move(hours)), power(std::move(power)),
78 energy(std::move(energy)) {}
79
80 vector<vector<double>> efficiency;
81 vector<vector<double>> hours;
82 vector<vector<double>> power;
83 vector<vector<double>> energy;
84 };
85
93 explicit ChillerPumpingEnergyOutput(vector<double> pumpingEnergy)
94 : chillerPumpingEnergy(std::move(pumpingEnergy)) {}
95
96 vector<double> chillerPumpingEnergy;
97 };
98
99 struct TowerOutput {
104 TowerOutput() = default;
105
113 TowerOutput(vector<double> hours, vector<double> energy) : hours(std::move(hours)), energy(std::move(energy)) {}
114
115 vector<double> tempBins = {35, 45, 55, 65, 75, 75};
116 vector<double> hours;
117 vector<double> energy;
118 };
119
126
138 WaterCooledSystemInput(double CHWT, bool useFreeCooling, double HEXApproachTemp, bool constantCWT, double CWT,
139 bool CWVariableFlow, double CWFlowRate, double CWTFollow)
140 : CHWT(CHWT), useFreeCooling(useFreeCooling), HEXApproachTemp(HEXApproachTemp), constantCWT(constantCWT),
141 CWT(CWT), CWVariableFlow(CWVariableFlow), CWFlowRate(CWFlowRate), CWTFollow(CWTFollow) {
142 isWaterCooled = true;
143 }
144
145 double CHWT = 44;
146 bool useFreeCooling = false;
147 double HEXApproachTemp = 0;
148 bool constantCWT = true;
149 double CWT = 85;
150 bool CWVariableFlow = true;
151 double CWFlowRate = 3;
152 double CWTFollow = 0;
153 bool isWaterCooled = false;
154 };
155
162
171 AirCooledSystemInput(double CHWT, double OADT, ACSourceLocation ACSource, double indoorTemp, double CWTFollow)
172 : CHWT(CHWT), OADT(OADT), ACSource(ACSource), indoorTemp(indoorTemp), CWTFollow(CWTFollow) {
173 isAirCooled = true;
174 }
175
176 double CHWT = 44;
177 double OADT = 95;
178 ACSourceLocation ACSource = ACSourceLocation::Outside;
179 double indoorTemp = 75;
180 double CWTFollow = 0;
181 bool isAirCooled = false;
182 };
183
184 struct PumpInput {
193 PumpInput(bool variableFlow, double flowRate, double efficiency, double motorSize, double motorEfficiency)
194 : variableFlow(variableFlow), flowRate(flowRate), efficiency(efficiency * 100), motorSize(motorSize),
195 motorEfficiency(motorEfficiency * 100) {}
196
197 bool variableFlow;
198 double flowRate;
199 double efficiency;
200 double motorSize;
201 double motorEfficiency;
202 };
203
204 struct TowerInput {
209 TowerInput() = default;
210
224 TowerInput(int numTower, int numFanPerTower_Cells, FanMotorSpeedType fanSpeedType, TowerSizedBy towerSizing,
225 CellFanType towerCellFanType, double cellFanHP, double tonnage)
226 : numTower(numTower), numFanPerTower_Cells(numFanPerTower_Cells), fanSpeedType(fanSpeedType), towerSizing(towerSizing),
227 towerCellFanType(towerCellFanType), fanHP(cellFanHP), tonnage(tonnage) {}
228
229 int numTower;
230 int numFanPerTower_Cells;
231 FanMotorSpeedType fanSpeedType;
232 TowerSizedBy towerSizing;
233 CellFanType towerCellFanType;
234 double fanHP;
235 double tonnage;
236 };
237
254 ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff,
255 double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector<vector<double>> monthlyLoads)
256 : chillerType(chillerType), capacity(capacity), isFullLoadEffKnown(isFullLoadEffKnown),
257 fullLoadEff(fullLoadEff), age(age), installVSD(installVSD),
258 useARIMonthlyLoadSchedule(useARIMonthlyLoadSchedule), monthlyLoads(std::move(monthlyLoads)),
259 isCustomChiller(false), loadAtPercent({}), kwPerTonLoads({}), changeRefrig(false),
260 currentRefrig(RefrigerantType::R_11), proposedRefrig(RefrigerantType::R_11) {
261 InitNonVaryingMonthlyLoad();
262 }
263
283 ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff,
284 double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector<vector<double>> monthlyLoads,
285 bool changeRefrig, RefrigerantType currentRefrig, RefrigerantType proposedRefrig)
286 : chillerType(chillerType), capacity(capacity), isFullLoadEffKnown(isFullLoadEffKnown),
287 fullLoadEff(fullLoadEff), age(age), installVSD(installVSD),
288 useARIMonthlyLoadSchedule(useARIMonthlyLoadSchedule), monthlyLoads(std::move(monthlyLoads)),
289 isCustomChiller(false), loadAtPercent({}), kwPerTonLoads({}), changeRefrig(changeRefrig),
290 currentRefrig(currentRefrig), proposedRefrig(proposedRefrig) {
291 InitNonVaryingMonthlyLoad();
292 }
293
312 ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff,
313 double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector<vector<double>> monthlyLoads,
314 RefrigerantType currentRefrig, RefrigerantType proposedRefrig)
315 : chillerType(chillerType), capacity(capacity), isFullLoadEffKnown(isFullLoadEffKnown),
316 fullLoadEff(fullLoadEff), age(age), installVSD(installVSD),
317 useARIMonthlyLoadSchedule(useARIMonthlyLoadSchedule), monthlyLoads(std::move(monthlyLoads)),
318 isCustomChiller(false), loadAtPercent({}), kwPerTonLoads({}), changeRefrig(true),
319 currentRefrig(currentRefrig), proposedRefrig(proposedRefrig) {
320 InitNonVaryingMonthlyLoad();
321 }
322
341 ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff,
342 double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector<vector<double>> monthlyLoads,
343 vector<double> loadAtPercent, vector<double> kwPerTonLoads)
344 : chillerType(chillerType), capacity(capacity), isFullLoadEffKnown(isFullLoadEffKnown),
345 fullLoadEff(fullLoadEff), age(age), installVSD(installVSD),
346 useARIMonthlyLoadSchedule(useARIMonthlyLoadSchedule), monthlyLoads(std::move(monthlyLoads)),
347 isCustomChiller(true), loadAtPercent(std::move(loadAtPercent)), kwPerTonLoads(std::move(kwPerTonLoads)),
348 changeRefrig(false), currentRefrig(RefrigerantType::R_11), proposedRefrig(RefrigerantType::R_11) {
349 InitNonVaryingMonthlyLoad();
350 SetCustomCoefficient();
351 }
352
374 ChillerInput(ChillerCompressorType chillerType, double capacity, bool isFullLoadEffKnown, double fullLoadEff,
375 double age, bool installVSD, bool useARIMonthlyLoadSchedule, vector<vector<double>> monthlyLoads,
376 vector<double> loadAtPercent, vector<double> kwPerTonLoads, RefrigerantType currentRefrig,
377 RefrigerantType proposedRefrig)
378 : chillerType(chillerType), capacity(capacity), isFullLoadEffKnown(isFullLoadEffKnown),
379 fullLoadEff(fullLoadEff), age(age), installVSD(installVSD),
380 useARIMonthlyLoadSchedule(useARIMonthlyLoadSchedule), monthlyLoads(std::move(monthlyLoads)),
381 isCustomChiller(true), loadAtPercent(std::move(loadAtPercent)), kwPerTonLoads(std::move(kwPerTonLoads)),
382 changeRefrig(true), currentRefrig(currentRefrig), proposedRefrig(proposedRefrig) {
383 InitNonVaryingMonthlyLoad();
384 SetCustomCoefficient();
385 }
386
387 ChillerCompressorType chillerType;
388 double capacity;
389 bool isFullLoadEffKnown;
390 double fullLoadEff;
391 double age;
392 bool installVSD;
393 bool useARIMonthlyLoadSchedule;
394 vector<vector<double>> monthlyLoads;
395
396 bool isCustomChiller;
397 vector<double> loadAtPercent;
398 vector<double> kwPerTonLoads;
399
400 bool changeRefrig = false;
401 RefrigerantType currentRefrig;
402 RefrigerantType proposedRefrig;
403
404 vector<double> customCoeffs;
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
444 size = static_cast<int>(coeff.size());
445 customCoeffs.resize(size, 0);
446 for (int i = 0; i < size; i++) {
447 customCoeffs[i] = coeff[i];
448 }
449 }
450
451 static vector<double> solveForCoefficients(const vector<double>& x, vector<double> y) {
452 if (x.empty() || x.size() != y.size())
453 return {};
454
455 const int n = static_cast<int>(x.size());
456
457 vector<vector<double>> a(n, vector<double>(n, 0));
458 for (int i = 0; i < n; ++i) {
459 for (int j = 0; j < n; ++j) {
460 a[i][j] = pow(x[i], n - 1 - j);
461 }
462 }
463
464 // Forward Elimination
465 for (int k = 0; k < n - 1; ++k) {
466 for (int i = k + 1; i < n; ++i) {
467 double factor = a[i][k] / a[k][k];
468 for (int j = k + 1; j < n; ++j) {
469 a[i][j] -= factor * a[k][j];
470 }
471 y[i] -= factor * y[k];
472 }
473 }
474
475 // Back Substitution
476 vector<double> coeff(n, 0);
477 coeff[n - 1] = y[n - 1] / a[n - 1][n - 1];
478 for (int i = n - 2; i >= 0; --i) {
479 double sum = y[i];
480 for (int j = i + 1; j < n; ++j) {
481 sum -= a[i][j] * coeff[j];
482 }
483 coeff[i] = sum / a[i][i];
484 }
485
486 return coeff;
487 }
488 };
489
490 ~ProcessCooling() = default;
491
506 ProcessCooling(const vector<int>& systemOperationAnnualHours, const vector<double>& weatherDryBulbHourlyTemp,
507 const vector<double>& weatherWetBulbHourlyTemp, const vector<ChillerInput>& chillerInputList,
508 const TowerInput& towerInput, const WaterCooledSystemInput& waterCooledSystemInput)
509 : ProcessCooling(systemOperationAnnualHours, weatherDryBulbHourlyTemp, weatherWetBulbHourlyTemp,
510 chillerInputList, {}, towerInput, waterCooledSystemInput) {}
511
523 ProcessCooling(const vector<int>& systemOperationAnnualHours, const vector<double>& weatherDryBulbHourlyTemp,
524 const vector<double>& weatherWetBulbHourlyTemp, const vector<ChillerInput>& chillerInputList,
525 const AirCooledSystemInput& airCooledSystemInput)
526 : ProcessCooling(systemOperationAnnualHours, weatherDryBulbHourlyTemp, weatherWetBulbHourlyTemp,
527 chillerInputList, airCooledSystemInput, {}, {}) {}
528
534
540
547
559 static vector<int> getSysOpAnnualHours(const vector<int>& weeklyOpStartHour, const vector<int>& weeklyOpStopHour, const vector<int>& monthlyOpMaxHour);
560
569 vector<double> getChillerEfficiencyCoeffs(int chillerIndex) const;
570
578 vector<double> getChillerEnergyEfficiency(int chillerIndex, const vector<double>& loadAtPercent) const;
579
580 private:
581 ProcessCooling(const vector<int>& systemOperationAnnualHours, const vector<double>& weatherDryBulbHourlyTemp,
582 const vector<double>& weatherWetBulbHourlyTemp, const vector<ChillerInput>& chillerInputList,
583 const AirCooledSystemInput& airCooledSystemInput, const TowerInput& towerInput,
584 const WaterCooledSystemInput& waterCooledSystemInput);
585
586 vector<int> systemOperationAnnual;
587 vector<double> dryBulbHourlyTemp;
588 vector<double> wetBulbHourlyTemp;
589
590 TowerInput tower {};
591 WaterCooledSystemInput waterCooledSystem;
592 AirCooledSystemInput airCooledSystem;
593 CoolingSystemType coolingType;
594
595 double FCTemp = 0; // Free Cooling Temperature
596 vector<double> CWTHourly;
597
598 int numChillers;
599 vector<ChillerInput> chillers;
600 vector<vector<double>> chillerHourlyLoad;
601 vector<vector<double>> chillerHourlyLoadOperational;
602 vector<vector<double>> chillerEfficiencyCoeffs;
603 vector<vector<double>> chillerHourlyEfficiencyARI;
604 vector<vector<double>> chillerHourlyEfficiency;
605 vector<vector<double>> chillerHourlyPower;
606
607 int getChillerCapacityIndex(ChillerCompressorType chillerType, double capacity) const;
608
609 double getChillerEffAtLoad(int c, double load, bool isFullLoadEffKnown) const;
610
611 void annualChillerLoadProfile();
612
613 void annualChillerEfficiencyProfileARI();
614
615 void annualChillerEfficiencyProfile();
616
617 void annualChillerPowerProfile();
618
619 void setTowerFanHPTonnage();
620
621 double getPercentFanPower(double wetBulbTemp, double percentWaterFlow, double range, double desiredApproach,
622 int yearHourIndex);
623
624 double getPercentWaterFlow(int yearHourIndex) const;
625
626 double getRange(int yearHourIndex) const;
627
628 double getApproach(double wetBulbTemp) const;
629
630 double modifyPercentFanPower(double percentFanPower) const;
631
632 double getWeightedAverageChillerLoad(int yearHourIndex) const;
633
634 double getChillerTonnageTotal() const;
635
636 static double getCubeRoot(double number);
637
638 static double getPumpHP(double power);
639};
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
vector< double > getChillerEnergyEfficiency(int chillerIndex, const vector< double > &loadAtPercent) const
static vector< int > getSysOpAnnualHours(const vector< int > &weeklyOpStartHour, const vector< int > &weeklyOpStopHour, const vector< int > &monthlyOpMaxHour)
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)