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
dryer_operating_cost.h
Go to the documentation of this file.
1#pragma once
2
21#include <cmath>
22#include <map>
23#include <stdexcept>
24
25#include "physics/constants.h"
26#include "physics/gas_constants.h"
27
29 public:
30 enum DryerType {
31 Heatless,
32 HeatedExternally,
33 BlowerPurgeWithSweep,
34 BlowerPurgeWithoutSweep,
35 HeatOfCompressionHC,
36 HeatOfCompressionSP,
37 Refrigerated
38 };
39
49 struct Output {
50 Output(const double waterRemoved, const double totalCostPerYear,
51 const double heaterPower, const double heatingHoursPerDay, const double purgeRate, const double designDDCPercentage):
52 waterRemoved(waterRemoved), totalCostPerYear(totalCostPerYear),
53 heaterPower(heaterPower), heatingHoursPerDay(heatingHoursPerDay), purgeRate(purgeRate), designDDCPercentage(designDDCPercentage){}
54
55 const double waterRemoved, totalCostPerYear, heaterPower, heatingHoursPerDay, purgeRate, designDDCPercentage;
56 };
57
87 struct Input {
88 double flowRate, pressure, temperature;
89 double operatingHoursPerDay, operatingDaysPerWeek, operatingWeeksPerYear;
90 double costOfElectricity, costOfCompressedAir, costOfCoolingWater;
91 double heaterPower, heatingHoursPerDay, purgeRate, designDDCPercentage;
92 };
93
99 explicit DryerOperatingCost(const Input& input) : DryerOperatingCost(input.flowRate, input.pressure, input.temperature,
100 input.operatingHoursPerDay, input.operatingDaysPerWeek, input.operatingWeeksPerYear,
101 input.costOfElectricity, input.costOfCompressedAir, input.costOfCoolingWater,
102 input.heaterPower, input.heatingHoursPerDay, input.purgeRate, input.designDDCPercentage) {}
103
116 DryerOperatingCost(const double flowRate, const double pressure, const double temperature,
117 const double operatingHoursPerDay, const double operatingDaysPerWeek, const double operatingWeeksPerYear,
118 const double costOfElectricity, const double costOfCompressedAir, const double costOfCoolingWater) :
119 DryerOperatingCost(flowRate, pressure, temperature,
120 operatingHoursPerDay, operatingDaysPerWeek, operatingWeeksPerYear,
121 costOfElectricity, costOfCompressedAir, costOfCoolingWater,
122 0.0, 0.0, 0.0, 0.0) {}
123
153 DryerOperatingCost(const double flowRate, const double pressure, const double temperature,
154 const double operatingHoursPerDay, const double operatingDaysPerWeek, const double operatingWeeksPerYear,
155 const double costOfElectricity, const double costOfCompressedAir, const double costOfCoolingWater,
156 const double heaterPower, const double heatingHoursPerDay, const double purgeRate, const double designDDCPercentage) :
157 flowRate(flowRate), pressure(pressure), temperature(temperature),
158 operatingHoursPerDay(operatingHoursPerDay), operatingDaysPerWeek(operatingDaysPerWeek), operatingWeeksPerYear(operatingWeeksPerYear),
159 costOfElectricity(costOfElectricity), costOfCompressedAir(costOfCompressedAir), costOfCoolingWater(costOfCoolingWater),
160 heaterPower(heaterPower), heatingHoursPerDay(heatingHoursPerDay), purgeRate(purgeRate), designDDCPercent(designDDCPercentage) {
161 if (flowRate < 1 || flowRate > 50000) {
162 throw std::invalid_argument("Flow rate must be between 1 and 50,000 SCFM.");
163 }
164 if (pressure < 25 || pressure > 150) {
165 throw std::invalid_argument("Pressure must be between 25 and 150 psig.");
166 }
167 if (temperature < 50 || temperature > 120) {
168 throw std::invalid_argument("Temperature must be between 50 and 120 F.");
169 }
170 if (operatingHoursPerDay < 1 || operatingHoursPerDay > 24) {
171 throw std::invalid_argument("Operating hours per day must be between 1 and 24.");
172 }
173 if (operatingDaysPerWeek < 1 || operatingDaysPerWeek > 7) {
174 throw std::invalid_argument("Operating days per week must be between 1 and 7.");
175 }
176 if (operatingWeeksPerYear < 1 || operatingWeeksPerYear > 52) {
177 throw std::invalid_argument("Operating weeks per year must be between 1 and 52.");
178 }
179 if (costOfElectricity < 0.01 || costOfElectricity > 0.20) {
180 throw std::invalid_argument("Cost of electricity must be between $0.01 and $0.20 per kWh.");
181 }
182 if (costOfCompressedAir < 0.20 || costOfCompressedAir > 0.50) {
183 throw std::invalid_argument("Cost of compressed air must be between $0.20 and $0.50 per 1000 SCF.");
184 }
185 if (costOfCoolingWater < 0.25 || costOfCoolingWater > 10.00) {
186 throw std::invalid_argument("Cost of cooling water must be between $0.25 and $10.00 per 1000 gallons.");
187 }
188 if (heaterPower < 0 || heaterPower > 1000) {
189 throw std::invalid_argument("Heater power must be between 0 and 1000 kW.");
190 }
191 if (heatingHoursPerDay < 0 || heatingHoursPerDay > 24) {
192 throw std::invalid_argument("Heating hours per day must be between 0 and 24.");
193 }
194 if (purgeRate < 0 || purgeRate > 100) {
195 throw std::invalid_argument("Purge rate must be between 0 and 100%.");
196 }
197 if (designDDCPercentage < 0 || designDDCPercentage > 100) {
198 throw std::invalid_argument("Design DDC percentage must be between 0 and 100%.");
199 }
200
201 if (this->designDDCPercent == 0) {
202 this->designDDCPercent = 0.1633;
203 } else {
204 this->designDDCPercent = designDDCPercentage / 100;
205 }
206 }
207
213 Output calculate(const DryerType dryerType) const {
214 auto purgeRatePercentage = purgeRate / 100.0;
215 auto heaterKW = heaterPower;
216 auto heatingHrsPerDay = heatingHoursPerDay;
217
218 auto tempLookup = lookupTemp.find(static_cast<int>(std::round(temperature)))->second;
219 if (dryerType == Refrigerated) {
220 const auto tempLookup40 = lookupTemp.find(40)->second;
221 tempLookup -= tempLookup40;
222 }
223 auto const waterRemovedPPH = flowRate * 60 * gas_constants::kH2OMw * tempLookup / ((pressure + physics::us::kAtmosphericPressurePsi) * 379);
224 auto const waterRemovedPer4Hrs = waterRemovedPPH * 4;
225
226 double theoreticalDryerSizeRequired = 0.0;
227 if (dryerType == Heatless) {
228 theoreticalDryerSizeRequired = flowRate * (114.7 / (pressure + physics::us::kAtmosphericPressurePsi));
229 } else if (dryerType == Refrigerated) {
230 } else {
231 const auto desiccantRequired = waterRemovedPer4Hrs / designDDCPercent;
232 theoreticalDryerSizeRequired = desiccantRequired / 0.5784;
233 }
234
235 if (purgeRatePercentage == 0) {
236 if (dryerType == Heatless) {
237 purgeRatePercentage = 0.15;
238 } else if (dryerType == HeatedExternally || dryerType == BlowerPurgeWithSweep || dryerType == BlowerPurgeWithoutSweep) {
239 purgeRatePercentage = 0.07;
240 } else if (dryerType == HeatOfCompressionHC) {
241 purgeRatePercentage = 0.02;
242 }
243 }
244 auto const purgeSCFM = theoreticalDryerSizeRequired * purgeRatePercentage;
245
246 if (heaterKW == 0.0) {
247 if (dryerType == HeatedExternally) {
248 heaterKW = purgeSCFM * 60 * 0.0764 * 0.241 * (375 - temperature) / 3412;
249 } else if (dryerType == HeatOfCompressionHC) {
250 heaterKW = flowRate * 0.02 * 1.08 * 275 / 3412;
251 } else if (dryerType == BlowerPurgeWithSweep || dryerType == BlowerPurgeWithoutSweep) {
252 heaterKW = theoreticalDryerSizeRequired * 0.25 * 60 * 0.0764 * 0.241 * (375 - temperature) / 3412;
253 }
254 }
255 if (heatingHrsPerDay == 0) {
256 if (dryerType == HeatedExternally || dryerType == BlowerPurgeWithSweep || dryerType == BlowerPurgeWithoutSweep) {
257 heatingHrsPerDay = 18;
258 } else if (dryerType == HeatOfCompressionHC) {
259 heatingHrsPerDay = 3;
260 }
261 }
262
263 auto const kwhPerDay = heaterKW * heatingHrsPerDay;
264
265 double heaterElectricCostPerDay = 0.0;
266 if (dryerType == HeatedExternally || dryerType == HeatOfCompressionHC || dryerType == BlowerPurgeWithSweep || dryerType == BlowerPurgeWithoutSweep) {
267 heaterElectricCostPerDay = kwhPerDay * costOfElectricity;
268 }
269
270 double motorElectricCostPerDay = 0.0;
271 if (dryerType == BlowerPurgeWithSweep || dryerType == BlowerPurgeWithoutSweep) {
272 motorElectricCostPerDay = theoreticalDryerSizeRequired * 0.25 / 50 * 24 * costOfElectricity;
273
274 if (dryerType == BlowerPurgeWithSweep) {
275 motorElectricCostPerDay *= 0.75;
276 }
277 } else if (dryerType == Refrigerated) {
278 motorElectricCostPerDay = flowRate / 180 * 24 * costOfElectricity;
279 }
280
281 double controlsElectricCostPerDay = 100 * 0.024 * costOfElectricity;
282 if (dryerType == Refrigerated) {
283 controlsElectricCostPerDay = 0;
284 }
285
286 double compressedAirPurgeCostPerDay =0;
287 if (dryerType == BlowerPurgeWithoutSweep || dryerType == Refrigerated) {
288 } else {
289 const double costOfElectricityOnly = costOfElectricity * (1000.0 / 60 / 4.5 * 0.7457 / 0.9);
290 compressedAirPurgeCostPerDay = purgeSCFM * 60 * 24 * (costOfCompressedAir > costOfElectricityOnly ? costOfCompressedAir : costOfElectricityOnly) / 1000;
291
292 if (dryerType == BlowerPurgeWithSweep) {
293 compressedAirPurgeCostPerDay /= 4;
294 } else if (dryerType == HeatOfCompressionHC) {
295 compressedAirPurgeCostPerDay *= 1.5/4;
296 }
297 }
298
299 double coolingWaterCostPerDay = 0.0;
300 if (dryerType == Refrigerated) {
301 coolingWaterCostPerDay = flowRate / 1000 * 8 * 60 * 24 * costOfCoolingWater / 1000;
302 }
303
304 auto const totalDailyCost = heaterElectricCostPerDay + motorElectricCostPerDay + controlsElectricCostPerDay + compressedAirPurgeCostPerDay + coolingWaterCostPerDay;
305
306 auto const totalCostPerDay = totalDailyCost * operatingHoursPerDay / 24;
307 auto const totalCostPerWeek = totalCostPerDay * operatingDaysPerWeek;
308 auto const totalCostPerYear = totalCostPerWeek * operatingWeeksPerYear;
309
310 return {waterRemovedPPH, totalCostPerYear, heaterKW, heatingHrsPerDay, purgeRatePercentage*100, designDDCPercent*100};
311 }
312
313 private:
314 const double flowRate, pressure, temperature;
315 const double operatingHoursPerDay, operatingDaysPerWeek, operatingWeeksPerYear;
316 const double costOfElectricity, costOfCompressedAir, costOfCoolingWater;
317 const double heaterPower, heatingHoursPerDay, purgeRate;
318 double designDDCPercent = 0.1633;
319
320 const std::map<int, double> lookupTemp = {
321 {36, 0.10396}, {37, 0.10815}, {38, 0.11249}, {39, 0.11699}, {40, 0.12164},
322 {41, 0.12646}, {42, 0.13145}, {43, 0.1366}, {44, 0.14194}, {45, 0.14746},
323 {46, 0.15317}, {47, 0.15907}, {48, 0.16517}, {49, 0.17148}, {50, 0.17799},
324 {51, 0.18473}, {52, 0.19169}, {53, 0.19888}, {54, 0.2063}, {55, 0.21397},
325 {56, 0.22188}, {57, 0.23006}, {58, 0.23849}, {59, 0.2472}, {60, 0.25618},
326 {61, 0.26545}, {62, 0.27502}, {63, 0.28488}, {64, 0.29505}, {65, 0.30554},
327 {66, 0.31636}, {67, 0.3275}, {68, 0.339}, {69, 0.35084}, {70, 0.36304},
328 {71, 0.37561}, {72, 0.38856}, {73, 0.4019}, {74, 0.41564}, {75, 0.42979},
329 {76, 0.44435}, {77, 0.45935}, {78, 0.47478}, {79, 0.49066}, {80, 0.50701},
330 {81, 0.52382}, {82, 0.54112}, {83, 0.55892}, {84, 0.57722}, {85, 0.59604},
331 {86, 0.6154}, {87, 0.6353}, {88, 0.65575}, {89, 0.67678}, {90, 0.69838},
332 {91, 0.72059}, {92, 0.7434}, {93, 0.76684}, {94, 0.79091}, {95, 0.81564},
333 {96, 0.84103}, {97, 0.86711}, {98, 0.89388}, {99, 0.92137}, {100, 0.94959},
334 {101, 0.97854}, {102, 1.0083}, {103, 1.0388}, {104, 1.07}, {105, 1.1021},
335 {106, 1.1351}, {107, 1.1688}, {108, 1.2035}, {109, 1.239}, {110, 1.2754},
336 {111, 1.3128}, {112, 1.351}, {113, 1.3902}, {114, 1.4305}, {115, 1.4717},
337 {116, 1.5139}, {117, 1.5571}, {118, 1.6014}, {119, 1.6468}, {120, 1.6933},
338 {121, 1.7409}, {122, 1.7897}, {123, 1.8396}, {124, 1.8907}, {125, 1.943},
339 {126, 1.9966}, {127, 2.0514}, {128, 2.1075}, {129, 2.1649}, {130, 2.2237}
340 };
341};
DryerOperatingCost(const double flowRate, const double pressure, const double temperature, const double operatingHoursPerDay, const double operatingDaysPerWeek, const double operatingWeeksPerYear, const double costOfElectricity, const double costOfCompressedAir, const double costOfCoolingWater)
DryerOperatingCost(const double flowRate, const double pressure, const double temperature, const double operatingHoursPerDay, const double operatingDaysPerWeek, const double operatingWeeksPerYear, const double costOfElectricity, const double costOfCompressedAir, const double costOfCoolingWater, const double heaterPower, const double heatingHoursPerDay, const double purgeRate, const double designDDCPercentage)
Output calculate(const DryerType dryerType) const
DryerOperatingCost(const Input &input)
Defines physical constants and unit conversions.
constexpr double kAtmosphericPressurePsi
Standard atmospheric pressure at sea level .
Definition constants.h:68