AMO-Tools-Suite  v.0.9.0
Set of tools for calculating energy efficiency in industrial equipment
All Classes Namespaces Files Functions Variables Enumerations Friends Macros Pages
calculator.h
1 // #ifndef AMO_TOOLS_SUITE_CALCULATOR_H
2 // #define AMO_TOOLS_SUITE_CALCULATOR_H
3 
4 #include <nan.h>
5 #include <node.h>
6 #include <string>
7 #include <stdexcept>
8 #include <array>
9 #include <cmath>
10 #include <vector>
11 #include <iostream>
12 #include "calculator/util/ElectricityReduction.h"
13 #include "calculator/util/NaturalGasReduction.h"
14 #include "calculator/util/CompressedAirReduction.h"
15 #include "calculator/util/CompressedAirLeakSurvey.h"
16 #include "calculator/util/CompressedAirPressureReduction.h"
17 #include "calculator/util/WaterReduction.h"
18 #include "calculator/util/insulation/pipes/InsulatedPipeInput.h"
19 #include "calculator/util/insulation/pipes/InsulatedPipeCalculator.h"
20 #include "calculator/util/insulation/pipes/InsulatedPipeOutput.h"
21 #include "calculator/util/insulation/tanks/InsulatedTankInput.h"
22 #include "calculator/util/insulation/tanks/InsulatedTankCalculator.h"
23 #include "calculator/util/insulation/tanks/InsulatedTankOutput.h"
24 
25 #include "ssmt/SaturatedProperties.h"
26 #include "ssmt/SteamSystemModelerTool.h"
27 #include "calculator/util/SteamReduction.h"
28 #include "calculator/util/Conversion.h"
29 
30 using namespace Nan;
31 using namespace v8;
32 
33 Local<Object> inp;
34 Local<Object> r;
35 
36 // double Get(std::string const &key)
37 // {
38 // Local<String> getName = Nan::New<String>(key).ToLocalChecked();
39 // auto rObj = Nan::To<Object>(inp).ToLocalChecked()->Get(GetCurrent(), getName);
40 // if (rObj->IsUndefined())
41 // {
42 // ThrowTypeError(std::string("Get method in calculator.h: " + key + " not present in object").c_str());
43 // }
44 // return Nan::To<double>(rObj).FromJust();
45 // }
46 
47 double GetDouble(std::string const &key, Local<Object> obj)
48 {
49  v8::Isolate *isolate = v8::Isolate::GetCurrent();
50  v8::Local<v8::Context> context = isolate->GetCurrentContext();
51  Local<String> getName = Nan::New<String>(key).ToLocalChecked();
52  Local<Value> rObj = Nan::To<Object>(obj).ToLocalChecked()->Get(context, getName).ToLocalChecked();
53  if (rObj->IsUndefined())
54  {
55  ThrowTypeError(std::string("GetDouble method in calculator.h: " + key + " not present in object").c_str());
56  }
57  return Nan::To<double>(rObj).FromJust();
58 }
59 
60 std::vector<double> GetVector(std::string const &key, Local<Object> obj)
61 {
62  v8::Isolate *isolate = v8::Isolate::GetCurrent();
63  v8::Local<v8::Context> context = isolate->GetCurrentContext();
64  Local<String> getName = Nan::New<String>(key).ToLocalChecked();
65  Local<Value> arrayTmp = Nan::To<Object>(obj).ToLocalChecked()->Get(context, getName).ToLocalChecked();
66  if (arrayTmp->IsUndefined())
67  {
68  ThrowTypeError(std::string("GetVector method in calculator.h: " + key + " not present in object").c_str());
69  }
70  Local<Array> jsArray = v8::Local<v8::Array>::Cast(arrayTmp);
71  std::vector<double> array;
72  for (unsigned int i = 0; i < jsArray->Length(); i++)
73  {
74  v8::Local<v8::Value> jsElement = jsArray->Get(context, i).ToLocalChecked();
75  double val = Nan::To<double>(jsElement).FromJust();
76  array.push_back(val);
77  }
78  return array;
79 }
80 
81 template <typename T>
82 T GetEnumVal(std::string const &key, Local<Object> obj)
83 {
84  v8::Isolate *isolate = v8::Isolate::GetCurrent();
85  v8::Local<v8::Context> context = isolate->GetCurrentContext();
86  Local<String> getName = Nan::New<String>(key).ToLocalChecked();
87  Local<Value> rObj = Nan::To<Object>(obj).ToLocalChecked()->Get(context, getName).ToLocalChecked();
88  if (rObj->IsUndefined())
89  {
90  ThrowTypeError(std::string("GetEnumVal method in calculator.h: Enum value " + key + " not present in object").c_str());
91  }
92  return static_cast<T>(Nan::To<double>(rObj).FromJust());
93 }
94 
95 bool GetBool(std::string const &key, Local<Object> obj)
96 {
97  v8::Isolate *isolate = v8::Isolate::GetCurrent();
98  v8::Local<v8::Context> context = isolate->GetCurrentContext();
99  Local<String> getName = Nan::New<String>(key).ToLocalChecked();
100  Local<Value> rObj = Nan::To<Object>(obj).ToLocalChecked()->Get(context, getName).ToLocalChecked();
101  if (rObj->IsUndefined())
102  {
103  ThrowTypeError(std::string("GetBool method in calculator.h: Boolean value " + key + " not present in object").c_str());
104  }
105  return Nan::To<bool>(rObj).FromJust();
106 }
107 
108 std::string GetStr(std::string const &key, Local<Object> obj)
109 {
110  v8::Isolate *isolate = v8::Isolate::GetCurrent();
111  v8::Local<v8::Context> context = isolate->GetCurrentContext();
112  Local<String> getName = Nan::New<String>(key).ToLocalChecked();
113  Local<Value> rObj = Nan::To<Object>(obj).ToLocalChecked()->Get(context, getName).ToLocalChecked();
114  if (rObj->IsUndefined())
115  {
116  ThrowTypeError(std::string("GetStr method in calculator.h: String " + key + " not present in object").c_str());
117  }
118  v8::String::Utf8Value s(isolate, rObj);
119  return std::string(*s);
120 }
121 
122 //NAN function for checking if an object parameter has been defined with a value
123 bool isDefined(Local<Object> obj, std::string const &key)
124 {
125  v8::Isolate *isolate = v8::Isolate::GetCurrent();
126  v8::Local<v8::Context> context = isolate->GetCurrentContext();
127  Local<String> getName = Nan::New<String>(key).ToLocalChecked();
128  Local<Value> rObj = Nan::To<Object>(obj).ToLocalChecked()->Get(context, getName).ToLocalChecked();
129  return !rObj->IsUndefined();
130 }
131 
132 //NAN function for binding DOUBLE data to anonymous object
133 inline void SetR(const std::string &key, double val)
134 {
135  Nan::Set(r, Nan::New<String>(key).ToLocalChecked(), Nan::New<Number>(val));
136 }
137 
138 // ============== Electricity Reduction ==============
139 
140 MultimeterData getMultimeterData(Local<Object> obj)
141 {
142  v8::Isolate *isolate = v8::Isolate::GetCurrent();
143  v8::Local<v8::Context> context = isolate->GetCurrentContext();
144  Local<String> getName = Nan::New<String>("multimeterData").ToLocalChecked();
145  Local<Object> multimeterDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
146  if (multimeterDataV8->IsUndefined())
147  {
148  ThrowTypeError(std::string("ElectricityReduction: getMultimeterData method in calculator.h: multimeterData not present in object").c_str());
149  }
150  int numberOfPhases = static_cast<int>(GetDouble("numberOfPhases", multimeterDataV8));
151  double supplyVoltage = GetDouble("supplyVoltage", multimeterDataV8);
152  double averageCurrent = GetDouble("averageCurrent", multimeterDataV8);
153  double powerFactor = GetDouble("powerFactor", multimeterDataV8);
154  return {
155  numberOfPhases,
156  supplyVoltage,
157  averageCurrent,
158  powerFactor};
159 }
160 
161 NameplateData getNameplateData(Local<Object> obj)
162 {
163  v8::Isolate *isolate = v8::Isolate::GetCurrent();
164  v8::Local<v8::Context> context = isolate->GetCurrentContext();
165  Local<String> getName = Nan::New<String>("nameplateData").ToLocalChecked();
166  Local<Object> nameplateDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
167  if (nameplateDataV8->IsUndefined())
168  {
169  ThrowTypeError(std::string("ElectricityReduction: getNameplateData method in calculator.h: nameplateData not present in object").c_str());
170  }
171  double ratedMotorPower = GetDouble("ratedMotorPower", nameplateDataV8);
172  bool variableSpeedMotor = GetBool("variableSpeedMotor", nameplateDataV8);
173  double operationalFrequency = GetDouble("operationalFrequency", nameplateDataV8);
174  double lineFrequency = GetDouble("lineFrequency", nameplateDataV8);
175  double motorAndDriveEfficiency = GetDouble("motorAndDriveEfficiency", nameplateDataV8);
176  double loadFactor = GetDouble("loadFactor", nameplateDataV8);
177  return {
178  ratedMotorPower,
179  variableSpeedMotor,
180  operationalFrequency,
181  lineFrequency,
182  motorAndDriveEfficiency,
183  loadFactor};
184 }
185 
186 PowerMeterData getPowerMeterData(Local<Object> obj)
187 {
188  v8::Isolate *isolate = v8::Isolate::GetCurrent();
189  v8::Local<v8::Context> context = isolate->GetCurrentContext();
190  Local<String> getName = Nan::New<String>("powerMeterData").ToLocalChecked();
191  Local<Object> powerMeterDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
192  if (powerMeterDataV8->IsUndefined())
193  {
194  ThrowTypeError(std::string("ElectricityReduction: getPowerMeterData method in calculator.h: powerMeterData not present in object").c_str());
195  }
196  double power = GetDouble("power", powerMeterDataV8);
197  return {power};
198 }
199 
200 OtherMethodData getOtherMethodData(Local<Object> obj)
201 {
202  v8::Isolate *isolate = v8::Isolate::GetCurrent();
203  v8::Local<v8::Context> context = isolate->GetCurrentContext();
204  Local<String> getName = Nan::New<String>("otherMethodData").ToLocalChecked();
205  Local<Object> otherMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
206  if (otherMethodDataV8->IsUndefined())
207  {
208  ThrowTypeError(std::string("ElectricityReduction: getOtherMethodData method in calculator.h: otherMethodData not present in object").c_str());
209  }
210  double energy = GetDouble("energy", otherMethodDataV8);
211  return {energy};
212 }
213 
214 ElectricityReductionInput constructElectricityReductionInput(Local<Object> obj)
215 {
216  int operatingHours = static_cast<int>(GetDouble("operatingHours", obj));
217  double electricityCost = GetDouble("electricityCost", obj);
218  int measurementMethod = static_cast<int>(GetDouble("measurementMethod", obj));
219  MultimeterData multimeterData = getMultimeterData(obj);
220  NameplateData nameplateData = getNameplateData(obj);
221  PowerMeterData powerMeterData = getPowerMeterData(obj);
222  OtherMethodData otherMethodData = getOtherMethodData(obj);
223  int units = static_cast<int>(GetDouble("units", obj));
224  return {
225  operatingHours,
226  electricityCost,
227  measurementMethod,
228  multimeterData,
229  nameplateData,
230  powerMeterData,
231  otherMethodData,
232  units};
233 }
234 
235 std::vector<ElectricityReductionInput> getElectricityReductionInputVec()
236 {
237  v8::Isolate *isolate = v8::Isolate::GetCurrent();
238  v8::Local<v8::Context> context = isolate->GetCurrentContext();
239  Local<String> getName = Nan::New<String>("electricityReductionInputVec").ToLocalChecked();
240  Local<Value> arrayTmp = Nan::To<Object>(inp).ToLocalChecked()->Get(context, getName).ToLocalChecked();
241  if (arrayTmp->IsUndefined())
242  {
243  ThrowTypeError(std::string("ElectricityReduction: getElectricityReductionInputVector method in calculator.h: electricityReductionInputVec not present in object").c_str());
244  }
245  Local<Array> electricityReductionInputArray = v8::Local<v8::Array>::Cast(arrayTmp);
246  std::vector<ElectricityReductionInput> inputVec;
247  for (std::size_t i = 0; i < electricityReductionInputArray->Length(); i++)
248  {
249  inputVec.emplace_back(constructElectricityReductionInput(Nan::To<Object>(electricityReductionInputArray->Get(context, i).ToLocalChecked()).ToLocalChecked()));
250  }
251  return inputVec;
252 }
253 
254 NAN_METHOD(electricityReduction)
255 {
256  inp = Nan::To<Object>(info[0]).ToLocalChecked();
257  r = Nan::New<Object>();
258  try
259  {
260  std::vector<ElectricityReductionInput> inputVec = getElectricityReductionInputVec();
261  ElectricityReduction::Output rv = ElectricityReduction(inputVec).calculate();
262  SetR("energyUse", rv.energyUse);
263  SetR("energyCost", rv.energyCost);
264  SetR("power", rv.power);
265  }
266  catch (std::runtime_error const &e)
267  {
268  std::string const what = e.what();
269  ThrowError(std::string("std::runtime_error thrown in electricityReduction - calculator.h: " + what).c_str());
270  }
271  info.GetReturnValue().Set(r);
272 }
273 // ============== END Electricity Reduction ==============
274 
275 // ============== Natural Gas ==============
276 
277 FlowMeterMethodData getFlowMeterMethodData(Local<Object> obj)
278 {
279  v8::Isolate *isolate = v8::Isolate::GetCurrent();
280  v8::Local<v8::Context> context = isolate->GetCurrentContext();
281  Local<String> getName = Nan::New<String>("flowMeterMethodData").ToLocalChecked();
282  Local<Object> flowMeterMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
283  if (flowMeterMethodDataV8->IsUndefined())
284  {
285  ThrowTypeError(std::string("NaturalGasReduction: getFlowMeterMethodData method in calculator.h: flowMeterMethodData not present in object").c_str());
286  }
287  double flowRate = GetDouble("flowRate", flowMeterMethodDataV8);
288  return {flowRate};
289 }
290 
291 AirMassFlowMeasuredData getAirMassFlowMeasuredData(Local<Object> obj)
292 {
293  v8::Isolate *isolate = v8::Isolate::GetCurrent();
294  v8::Local<v8::Context> context = isolate->GetCurrentContext();
295  Local<String> getName = Nan::New<String>("airMassFlowMeasuredData").ToLocalChecked();
296  Local<Object> airMassFlowMeasuredDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
297  if (airMassFlowMeasuredDataV8->IsUndefined())
298  {
299  ThrowTypeError(std::string("NaturalGasReduction: getAirMassFlowMeasuredData method in calculator.h: airMassFlowMeasuredData not present in object").c_str());
300  }
301  double areaOfDuct = GetDouble("areaOfDuct", airMassFlowMeasuredDataV8);
302  double airVelocity = GetDouble("airVelocity", airMassFlowMeasuredDataV8);
303  return {
304  areaOfDuct,
305  airVelocity};
306 }
307 
308 AirMassFlowNameplateData getAirMassFlowNameplateData(Local<Object> obj)
309 {
310  v8::Isolate *isolate = v8::Isolate::GetCurrent();
311  v8::Local<v8::Context> context = isolate->GetCurrentContext();
312  Local<String> getName = Nan::New<String>("airMassFlowNameplateData").ToLocalChecked();
313  Local<Object> airMassFlowNameplateDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
314  if (airMassFlowNameplateDataV8->IsUndefined())
315  {
316  ThrowTypeError(std::string("NaturalGasReduction: getAirMassFlowNameplateData method in calculator.h: airMassFlowNameplateData not present in object").c_str());
317  }
318  double airFlow = GetDouble("airFlow", airMassFlowNameplateDataV8);
319  return {
320  airFlow};
321 }
322 
323 AirMassFlowData getAirMassFlowData(Local<Object> obj)
324 {
325  v8::Isolate *isolate = v8::Isolate::GetCurrent();
326  v8::Local<v8::Context> context = isolate->GetCurrentContext();
327  Local<String> getName = Nan::New<String>("airMassFlowData").ToLocalChecked();
328  Local<Object> airMassFlowDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
329  if (airMassFlowDataV8->IsUndefined())
330  {
331  ThrowTypeError(std::string("NaturalGasReduction: getAirMassFlowData method in calculator.h: airMassFlowData not present in object").c_str());
332  }
333  bool isNameplate = GetBool("isNameplate", airMassFlowDataV8);
334  AirMassFlowMeasuredData measuredData = getAirMassFlowMeasuredData(airMassFlowDataV8);
335  AirMassFlowNameplateData nameplateData = getAirMassFlowNameplateData(airMassFlowDataV8);
336  double inletTemperature = GetDouble("inletTemperature", airMassFlowDataV8);
337  double outletTemperature = GetDouble("outletTemperature", airMassFlowDataV8);
338  double systemEfficiency = Conversion(GetDouble("systemEfficiency", airMassFlowDataV8)).percentToFraction();
339  return {
340  isNameplate,
341  measuredData,
342  nameplateData,
343  inletTemperature,
344  outletTemperature,
345  systemEfficiency};
346 }
347 
348 WaterMassFlowData getWaterMassFlowData(Local<Object> obj)
349 {
350  v8::Isolate *isolate = v8::Isolate::GetCurrent();
351  v8::Local<v8::Context> context = isolate->GetCurrentContext();
352  Local<String> getName = Nan::New<String>("waterMassFlowData").ToLocalChecked();
353  Local<Object> waterMassFlowDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
354  if (waterMassFlowDataV8->IsUndefined())
355  {
356  ThrowTypeError(std::string("NaturalGasReduction: getWaterMassFlowData method in calculator.h: waterMassFlowData not present in object").c_str());
357  }
358  double waterFlow = GetDouble("waterFlow", waterMassFlowDataV8);
359  double inletTemperature = GetDouble("inletTemperature", waterMassFlowDataV8);
360  double outletTemperature = GetDouble("outletTemperature", waterMassFlowDataV8);
361  double systemEfficiency = Conversion(GetDouble("systemEfficiency", waterMassFlowDataV8)).percentToFraction();
362  return {
363  waterFlow,
364  inletTemperature,
365  outletTemperature,
366  systemEfficiency};
367 }
368 
369 NaturalGasOtherMethodData naturalGasGetOtherMethodData(Local<Object> obj)
370 {
371  v8::Isolate *isolate = v8::Isolate::GetCurrent();
372  v8::Local<v8::Context> context = isolate->GetCurrentContext();
373  Local<String> getName = Nan::New<String>("otherMethodData").ToLocalChecked();
374  Local<Object> otherMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
375  if (otherMethodDataV8->IsUndefined())
376  {
377  ThrowTypeError(std::string("NaturalGasReduction: naturalGasGetOtherMethodData method in calculator.h: otherMethodData not present in object").c_str());
378  }
379  double consumption = GetDouble("consumption", otherMethodDataV8);
380  return {
381  consumption};
382 }
383 
384 NaturalGasReductionInput constructNaturalGasReductionInput(Local<Object> obj)
385 {
386  int operatingHours = static_cast<int>(GetDouble("operatingHours", obj));
387  double fuelCost = GetDouble("fuelCost", obj);
388  int measurementMethod = static_cast<int>(GetDouble("measurementMethod", obj));
389  FlowMeterMethodData flowMeterMethodData = getFlowMeterMethodData(obj);
390  NaturalGasOtherMethodData otherMethodData = naturalGasGetOtherMethodData(obj);
391  AirMassFlowData airMassFlowData = getAirMassFlowData(obj);
392  WaterMassFlowData waterMassFlowData = getWaterMassFlowData(obj);
393  int units = static_cast<int>(GetDouble("units", obj));
394  return {
395  operatingHours,
396  fuelCost,
397  measurementMethod,
398  flowMeterMethodData,
399  otherMethodData,
400  airMassFlowData,
401  waterMassFlowData,
402  units};
403 }
404 
405 std::vector<NaturalGasReductionInput> getNaturalGasReductionInputVec()
406 {
407  v8::Isolate *isolate = v8::Isolate::GetCurrent();
408  v8::Local<v8::Context> context = isolate->GetCurrentContext();
409  Local<String> getName = Nan::New<String>("naturalGasReductionInputVec").ToLocalChecked();
410  Local<Value> arrayTmp = Nan::To<Object>(inp).ToLocalChecked()->Get(context, getName).ToLocalChecked();
411  if (arrayTmp->IsUndefined())
412  {
413  ThrowTypeError(std::string("NaturalGasReduction: getNaturalGasReductionInputVector method in calculator.h: naturalGasReductionInputVec not present in object").c_str());
414  }
415  Local<Array> naturalGasReductionInputArray = v8::Local<v8::Array>::Cast(arrayTmp);
416  std::vector<NaturalGasReductionInput> inputVec;
417  for (std::size_t i = 0; i < naturalGasReductionInputArray->Length(); i++)
418  {
419  inputVec.emplace_back(constructNaturalGasReductionInput(Nan::To<Object>(naturalGasReductionInputArray->Get(context, i).ToLocalChecked()).ToLocalChecked()));
420  }
421  return inputVec;
422 }
423 
424 NAN_METHOD(naturalGasReduction)
425 {
426  inp = Nan::To<Object>(info[0]).ToLocalChecked();
427  r = Nan::New<Object>();
428  try
429  {
430  std::vector<NaturalGasReductionInput> inputVec = getNaturalGasReductionInputVec();
431  NaturalGasReduction::Output rv = NaturalGasReduction(inputVec).calculate();
432  SetR("energyUse", rv.energyUse);
433  SetR("energyCost", rv.energyCost);
434  SetR("heatFlow", rv.heatFlow);
435  SetR("totalFlow", rv.totalFlow);
436  }
437  catch (std::runtime_error const &e)
438  {
439  std::string const what = e.what();
440  ThrowError(std::string("std::runtime_error thrown in naturalGasReduction - calculator.h: " + what).c_str());
441  }
442  info.GetReturnValue().Set(r);
443 }
444 // ============== END Natural Gas ==============
445 
446 // ============== Compressed Air ==============
447 
448 CompressedAirFlowMeterMethodData getCompressedAirFlowMeterMethodData(Local<Object> obj)
449 {
450  v8::Isolate *isolate = v8::Isolate::GetCurrent();
451  v8::Local<v8::Context> context = isolate->GetCurrentContext();
452  Local<String> getName = Nan::New<String>("flowMeterMethodData").ToLocalChecked();
453  Local<Object> flowMeterMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
454  if (flowMeterMethodDataV8->IsUndefined())
455  {
456  ThrowTypeError(std::string("CompressedAirReduction: getCompressedAirFlowMeterMethodData method in calculator.h: flowMeterMethodData not present in object").c_str());
457  }
458  double meterReading = GetDouble("meterReading", flowMeterMethodDataV8);
459  return {meterReading};
460 }
461 
462 BagMethodData getBagMethodData(Local<Object> obj)
463 {
464  v8::Isolate *isolate = v8::Isolate::GetCurrent();
465  v8::Local<v8::Context> context = isolate->GetCurrentContext();
466  Local<String> getName = Nan::New<String>("bagMethodData").ToLocalChecked();
467  Local<Object> bagMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
468  if (bagMethodDataV8->IsUndefined())
469  {
470  ThrowTypeError(std::string("CompressedAirReduction: getBagMethodData method in calculator.h: bagMethodData not present in object").c_str());
471  }
472  double height = GetDouble("height", bagMethodDataV8);
473  double diameter = GetDouble("diameter", bagMethodDataV8);
474  double fillTime = GetDouble("fillTime", bagMethodDataV8);
475  return {
476  height,
477  diameter,
478  fillTime};
479 }
480 
481 PressureMethodData getPressureMethodData(Local<Object> obj)
482 {
483  v8::Isolate *isolate = v8::Isolate::GetCurrent();
484  v8::Local<v8::Context> context = isolate->GetCurrentContext();
485  Local<String> getName = Nan::New<String>("pressureMethodData").ToLocalChecked();
486  Local<Object> pressureMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
487  if (pressureMethodDataV8->IsUndefined())
488  {
489  ThrowTypeError(std::string("CompressedAirReduction: getPressureMethodData method in calculator.h: pressureMethodData not present in object").c_str());
490  }
491  int nozzleType = static_cast<int>(GetDouble("nozzleType", pressureMethodDataV8));
492  int numberOfNozzles = static_cast<int>(GetDouble("numberOfNozzles", pressureMethodDataV8));
493  double supplyPressure = GetDouble("supplyPressure", pressureMethodDataV8);
494  return {
495  nozzleType,
496  numberOfNozzles,
497  supplyPressure};
498 }
499 
500 CompressedAirOtherMethodData getCompressedAirOtherMethodData(Local<Object> obj)
501 {
502  v8::Isolate *isolate = v8::Isolate::GetCurrent();
503  v8::Local<v8::Context> context = isolate->GetCurrentContext();
504  Local<String> getName = Nan::New<String>("otherMethodData").ToLocalChecked();
505  Local<Object> otherMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
506  if (otherMethodDataV8->IsUndefined())
507  {
508  ThrowTypeError(std::string("CompressedAirReduction: getCompressedAirOtherMethodData method in calculator.h: otherMethodData not present in object").c_str());
509  }
510  double consumption = GetDouble("consumption", otherMethodDataV8);
511  return {consumption};
512 }
513 
514 CompressorElectricityData getCompressorElectricityData(Local<Object> obj, bool convert = true)
515 {
516  v8::Isolate *isolate = v8::Isolate::GetCurrent();
517  v8::Local<v8::Context> context = isolate->GetCurrentContext();
518  Local<String> getName = Nan::New<String>("compressorElectricityData").ToLocalChecked();
519  Local<Object> compressorElectricityDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
520  if (compressorElectricityDataV8->IsUndefined())
521  {
522  ThrowTypeError(std::string("CompressedAirReduction: getCompressorElectricityData method in calculator.h: compressorElectricityData not present in object").c_str());
523  }
524  double compressorControlAdjustment;
525  if (convert)
526  {
527  compressorControlAdjustment = Conversion(GetDouble("compressorControlAdjustment", compressorElectricityDataV8)).percentToFraction();
528  }
529  else
530  {
531  compressorControlAdjustment = GetDouble("compressorControlAdjustment", compressorElectricityDataV8);
532  }
533  double compressorSpecificPower = GetDouble("compressorSpecificPower", compressorElectricityDataV8);
534  return {
535  compressorControlAdjustment,
536  compressorSpecificPower};
537 }
538 
539 CompressedAirReductionInput constructCompressedAirReductionInput(Local<Object> obj)
540 {
541  int hoursPerYear = static_cast<int>(GetDouble("hoursPerYear", obj));
542  int utilityType = static_cast<int>(GetDouble("utilityType", obj));
543  double utilityCost = GetDouble("utilityCost", obj);
544  int measurementMethod = static_cast<int>(GetDouble("measurementMethod", obj));
545  CompressedAirFlowMeterMethodData airFlowData = getCompressedAirFlowMeterMethodData(obj);
546  BagMethodData bagMethodData = getBagMethodData(obj);
547  PressureMethodData pressureMethodData = getPressureMethodData(obj);
548  CompressedAirOtherMethodData otherMethodData = getCompressedAirOtherMethodData(obj);
549  CompressorElectricityData electricityData = getCompressorElectricityData(obj);
550  int units = static_cast<int>(GetDouble("units", obj));
551  return {
552  hoursPerYear,
553  utilityType,
554  utilityCost,
555  measurementMethod,
556  airFlowData,
557  bagMethodData,
558  pressureMethodData,
559  otherMethodData,
560  electricityData,
561  units};
562 }
563 
564 std::vector<CompressedAirReductionInput> getCompressedAirReductionInputVec()
565 {
566  v8::Isolate *isolate = v8::Isolate::GetCurrent();
567  v8::Local<v8::Context> context = isolate->GetCurrentContext();
568  Local<String> getName = Nan::New<String>("compressedAirReductionInputVec").ToLocalChecked();
569  Local<Value> arrayTmp = Nan::To<Object>(inp).ToLocalChecked()->Get(context, getName).ToLocalChecked();
570  if (arrayTmp->IsUndefined())
571  {
572  ThrowTypeError(std::string("CompressedAirReduction: getCompressedAirReductionInputVec method in calculator.h: compressedAirReductionInputVec not present in object").c_str());
573  }
574  Local<Array> compressedAirReductionInputArray = v8::Local<v8::Array>::Cast(arrayTmp);
575  std::vector<CompressedAirReductionInput> inputVec;
576  for (std::size_t i = 0; i < compressedAirReductionInputArray->Length(); i++)
577  {
578  inputVec.emplace_back(constructCompressedAirReductionInput(Nan::To<Object>(compressedAirReductionInputArray->Get(context, i).ToLocalChecked()).ToLocalChecked()));
579  }
580  return inputVec;
581 }
582 
583 NAN_METHOD(compressedAirReduction)
584 {
585  inp = Nan::To<Object>(info[0]).ToLocalChecked();
586  r = Nan::New<Object>();
587  try
588  {
589  std::vector<CompressedAirReductionInput> inputVec = getCompressedAirReductionInputVec();
590  CompressedAirReduction::Output rv = CompressedAirReduction(inputVec).calculate();
591  SetR("energyUse", rv.energyUse);
592  SetR("energyCost", rv.energyCost);
593  SetR("flowRate", rv.flowRate);
594  SetR("singleNozzleFlowRate", rv.singleNozzleFlowRate);
595  SetR("consumption", rv.consumption);
596  }
597  catch (std::runtime_error const &e)
598  {
599  std::string const what = e.what();
600  ThrowError(std::string("std::runtime_error thrown in compressedAirReduction - calculator.h: " + what).c_str());
601  }
602  info.GetReturnValue().Set(r);
603 }
604 
605 // ========== END Compressed Air ==============
606 
607 // ========== Start Air Leak Survey ===========
608 
609 EstimateMethodData getEstimateMethodData(Local<Object> obj)
610 {
611  v8::Isolate *isolate = v8::Isolate::GetCurrent();
612  v8::Local<v8::Context> context = isolate->GetCurrentContext();
613  Local<String> getName = Nan::New<String>("estimateMethodData").ToLocalChecked();
614  Local<Object> estimateMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
615  if (estimateMethodDataV8->IsUndefined())
616  {
617  ThrowTypeError(std::string("CompressedAirReduction: getEstimateMethodData method in calculator.h: estimateMethodData not present in object").c_str());
618  }
619  double leakRateEstimate = GetDouble("leakRateEstimate", estimateMethodDataV8);
620  return {
621  leakRateEstimate};
622 }
623 
624 DecibelsMethodData getDecibelsMethodData(Local<Object> obj)
625 {
626  v8::Isolate *isolate = v8::Isolate::GetCurrent();
627  v8::Local<v8::Context> context = isolate->GetCurrentContext();
628  Local<String> getName = Nan::New<String>("decibelsMethodData").ToLocalChecked();
629  Local<Object> decibelsMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
630  if (decibelsMethodDataV8->IsUndefined())
631  {
632  ThrowTypeError(std::string("CompressedAirReduction: getDecibelsMethodData method in calculator.h: decibelsMethodData not present in object").c_str());
633  }
634  double linePressure = GetDouble("linePressure", decibelsMethodDataV8);
635  double decibels = GetDouble("decibels", decibelsMethodDataV8);
636  double decibelRatingA = GetDouble("decibelRatingA", decibelsMethodDataV8);
637  double pressureA = GetDouble("pressureA", decibelsMethodDataV8);
638  double firstFlowA = GetDouble("firstFlowA", decibelsMethodDataV8);
639  double secondFlowA = GetDouble("secondFlowA", decibelsMethodDataV8);
640  double decibelRatingB = GetDouble("decibelRatingB", decibelsMethodDataV8);
641  double pressureB = GetDouble("pressureB", decibelsMethodDataV8);
642  double firstFlowB = GetDouble("firstFlowB", decibelsMethodDataV8);
643  double secondFlowB = GetDouble("secondFlowB", decibelsMethodDataV8);
644  return {
645  linePressure,
646  decibels,
647  decibelRatingA,
648  pressureA,
649  firstFlowA,
650  secondFlowA,
651  decibelRatingB,
652  pressureB,
653  firstFlowB,
654  secondFlowB};
655 }
656 
657 OrificeMethodData getOrificeMethodData(Local<Object> obj)
658 {
659  v8::Isolate *isolate = v8::Isolate::GetCurrent();
660  v8::Local<v8::Context> context = isolate->GetCurrentContext();
661  Local<String> getName = Nan::New<String>("orificeMethodData").ToLocalChecked();
662  Local<Object> orificeMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
663  if (orificeMethodDataV8->IsUndefined())
664  {
665  ThrowTypeError(std::string("CompressedAirReduction: getOrificeMethodData method in calculator.h: orificeMethodData not present in object").c_str());
666  }
667  double airTemp = GetDouble("compressorAirTemp", orificeMethodDataV8);
668  double atmPressure = GetDouble("atmosphericPressure", orificeMethodDataV8);
669  double dischargeCoef = GetDouble("dischargeCoefficient", orificeMethodDataV8);
670  double diameter = GetDouble("orificeDiameter", orificeMethodDataV8);
671  double supplyPressure = GetDouble("supplyPressure", orificeMethodDataV8);
672  int numOrifices = static_cast<int>(GetDouble("numberOfOrifices", orificeMethodDataV8));
673  return {
674  airTemp,
675  atmPressure,
676  dischargeCoef,
677  diameter,
678  supplyPressure,
679  numOrifices};
680 }
681 
682 CompressedAirLeakSurveyInput constructCompressedAirLeakSurveyInput(Local<Object> obj)
683 {
684  int hoursPerYear = static_cast<int>(GetDouble("hoursPerYear", obj));
685  int utilityType = static_cast<int>(GetDouble("utilityType", obj));
686  double utilityCost = GetDouble("utilityCost", obj);
687  int measurementMethod = static_cast<int>(GetDouble("measurementMethod", obj));
688  EstimateMethodData estimateMethodData = getEstimateMethodData(obj);
689  DecibelsMethodData decibelsMethodData = getDecibelsMethodData(obj);
690  BagMethodData bagMethodData = getBagMethodData(obj);
691  OrificeMethodData orificeMethodData = getOrificeMethodData(obj);
692  CompressorElectricityData electricityData = getCompressorElectricityData(obj, false);
693  int units = static_cast<int>(GetDouble("units", obj));
694  return {
695  hoursPerYear,
696  utilityType,
697  utilityCost,
698  measurementMethod,
699  estimateMethodData,
700  decibelsMethodData,
701  bagMethodData,
702  orificeMethodData,
703  electricityData,
704  units};
705 }
706 
707 std::vector<CompressedAirLeakSurveyInput> getCompressedAirLeakSurveyInputVec()
708 {
709  v8::Isolate *isolate = v8::Isolate::GetCurrent();
710  v8::Local<v8::Context> context = isolate->GetCurrentContext();
711  Local<String> getName = Nan::New<String>("compressedAirLeakSurveyInputVec").ToLocalChecked();
712  Local<Value> arrayTmp = Nan::To<Object>(inp).ToLocalChecked()->Get(context, getName).ToLocalChecked();
713  if (arrayTmp->IsUndefined())
714  {
715  ThrowTypeError(std::string("CompressedAirLeakSurvey: getCompressedAirLeakSurveyInputVec method in calculator.h: compressedAirLeakSurveyInputVec not present in object").c_str());
716  }
717  Local<Array> compressedAirLeakSurveyInputArray = v8::Local<v8::Array>::Cast(arrayTmp);
718  std::vector<CompressedAirLeakSurveyInput> inputVec;
719  for (std::size_t i = 0; i < compressedAirLeakSurveyInputArray->Length(); i++)
720  {
721  inputVec.emplace_back(constructCompressedAirLeakSurveyInput(Nan::To<Object>(compressedAirLeakSurveyInputArray->Get(context, i).ToLocalChecked()).ToLocalChecked()));
722  }
723  return inputVec;
724 }
725 
726 NAN_METHOD(compressedAirLeakSurvey)
727 {
728  inp = Nan::To<Object>(info[0]).ToLocalChecked();
729  r = Nan::New<Object>();
730  try
731  {
732  std::vector<CompressedAirLeakSurveyInput> inputVec = getCompressedAirLeakSurveyInputVec();
733  CompressedAirLeakSurvey::Output rv = CompressedAirLeakSurvey(inputVec).calculate();
734  SetR("annualTotalElectricity", rv.annualTotalElectricity);
735  SetR("annualTotalElectricityCost", rv.annualTotalElectricityCost);
736  SetR("totalFlowRate", rv.totalFlowRate);
737  SetR("annualTotalFlowRate", rv.annualTotalFlowRate);
738  }
739  catch (std::runtime_error const &e)
740  {
741  std::string const what = e.what();
742  ThrowError(std::string("std::runtime_error thrown in compressedAirLeakSurvey - calculator.h: " + what).c_str());
743  }
744  info.GetReturnValue().Set(r);
745 }
746 
747 // ========== END Air Leak Survey =============
748 
749 // ========== Start Water Reduction ===========
750 
751 MeteredFlowMethodData getMeteredFlowMethodData(Local<Object> obj)
752 {
753  v8::Isolate *isolate = v8::Isolate::GetCurrent();
754  v8::Local<v8::Context> context = isolate->GetCurrentContext();
755  Local<String> getName = Nan::New<String>("meteredFlowMethodData").ToLocalChecked();
756  Local<Object> meteredFlowMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
757  if (meteredFlowMethodDataV8->IsUndefined())
758  {
759  ThrowTypeError(std::string("WaterReduction: getMeteredFlowMethodData method in calculator.h: meteredFlowMethodData not present in object").c_str());
760  }
761  double meterReading = GetDouble("meterReading", meteredFlowMethodDataV8);
762  return {meterReading};
763 }
764 
765 VolumeMeterMethodData getVolumeMeterMethodData(Local<Object> obj)
766 {
767  v8::Isolate *isolate = v8::Isolate::GetCurrent();
768  v8::Local<v8::Context> context = isolate->GetCurrentContext();
769  Local<String> getName = Nan::New<String>("volumeMeterMethodData").ToLocalChecked();
770  Local<Object> volumeMeterMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
771  if (volumeMeterMethodDataV8->IsUndefined())
772  {
773  ThrowTypeError(std::string("WaterReduction: getVolumeMeterMethodData method in calculator.h: volumeMeterMethodData not present in object").c_str());
774  }
775  double finalMeterReading = GetDouble("finalMeterReading", volumeMeterMethodDataV8);
776  double initialMeterReading = GetDouble("initialMeterReading", volumeMeterMethodDataV8);
777  double elapsedTime = GetDouble("elapsedTime", volumeMeterMethodDataV8);
778  return {
779  finalMeterReading,
780  initialMeterReading,
781  elapsedTime};
782 }
783 
784 BucketMethodData getBucketMethodData(Local<Object> obj)
785 {
786  v8::Isolate *isolate = v8::Isolate::GetCurrent();
787  v8::Local<v8::Context> context = isolate->GetCurrentContext();
788  Local<String> getName = Nan::New<String>("bucketMethodData").ToLocalChecked();
789  Local<Object> bucketMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
790  if (bucketMethodDataV8->IsUndefined())
791  {
792  ThrowTypeError(std::string("WaterReduction: getBucketMethodData method in calculator.h: bucketMethodData not present in object").c_str());
793  }
794  double bucketVolume = GetDouble("bucketVolume", bucketMethodDataV8);
795  double bucketFillTime = GetDouble("bucketFillTime", bucketMethodDataV8);
796  return {
797  bucketVolume,
798  bucketFillTime};
799 }
800 
801 WaterOtherMethodData getWaterOtherMethodData(Local<Object> obj)
802 {
803  v8::Isolate *isolate = v8::Isolate::GetCurrent();
804  v8::Local<v8::Context> context = isolate->GetCurrentContext();
805  Local<String> getName = Nan::New<String>("otherMethodData").ToLocalChecked();
806  Local<Object> otherMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
807  if (otherMethodDataV8->IsUndefined())
808  {
809  ThrowTypeError(std::string("WaterReduction: getWaterOtherMethodData method in calculator.h: otherMethodData not present in object").c_str());
810  }
811  double consumption = GetDouble("consumption", otherMethodDataV8);
812  return {
813  consumption};
814 }
815 
816 WaterReductionInput constructWaterReductionInput(Local<Object> obj)
817 {
818  int hoursPerYear = static_cast<int>(GetDouble("hoursPerYear", obj));
819  double waterCost = GetDouble("waterCost", obj);
820  int measurementMethod = static_cast<int>(GetDouble("measurementMethod", obj));
821  MeteredFlowMethodData meteredFlowMethodData = getMeteredFlowMethodData(obj);
822  VolumeMeterMethodData volumeMeterMethodData = getVolumeMeterMethodData(obj);
823  BucketMethodData bucketMethodData = getBucketMethodData(obj);
824  WaterOtherMethodData otherMethodData = getWaterOtherMethodData(obj);
825  return {
826  hoursPerYear,
827  waterCost,
828  measurementMethod,
829  meteredFlowMethodData,
830  volumeMeterMethodData,
831  bucketMethodData,
832  otherMethodData};
833 }
834 
835 std::vector<WaterReductionInput> getWaterReductionInputVec()
836 {
837  v8::Isolate *isolate = v8::Isolate::GetCurrent();
838  v8::Local<v8::Context> context = isolate->GetCurrentContext();
839  Local<String> getName = Nan::New<String>("waterReductionInputVec").ToLocalChecked();
840  Local<Value> arrayTmp = Nan::To<Object>(inp).ToLocalChecked()->Get(context, getName).ToLocalChecked();
841  if (arrayTmp->IsUndefined())
842  {
843  ThrowTypeError(std::string("WaterReduction: getWaterReductionInputVec method in calculator.h: waterReductionInputVec not present in object").c_str());
844  }
845  Local<Array> waterReductionInputArray = v8::Local<v8::Array>::Cast(arrayTmp);
846  std::vector<WaterReductionInput> inputVec;
847  for (std::size_t i = 0; i < waterReductionInputArray->Length(); i++)
848  {
849  inputVec.emplace_back(constructWaterReductionInput(Nan::To<Object>(waterReductionInputArray->Get(context, i).ToLocalChecked()).ToLocalChecked()));
850  }
851  return inputVec;
852 }
853 
854 NAN_METHOD(waterReduction)
855 {
856  inp = Nan::To<Object>(info[0]).ToLocalChecked();
857  r = Nan::New<Object>();
858  try
859  {
860  std::vector<WaterReductionInput> inputVec = getWaterReductionInputVec();
861  WaterReduction::Output rv = WaterReduction(inputVec).calculate();
862  SetR("waterUse", rv.waterUse);
863  SetR("waterCost", rv.waterCost);
864  }
865  catch (std::runtime_error const &e)
866  {
867  std::string const what = e.what();
868  ThrowError(std::string("std::runtime_error thrown in waterReduction - calculator.h: " + what).c_str());
869  }
870  info.GetReturnValue().Set(r);
871 }
872 
873 // ========== END water reduction =============
874 
875 // ========== Start CA Pressure Reduction ===========
876 CompressedAirPressureReductionInput constructCompressedAirPressureReductionInput(Local<Object> obj)
877 {
878  bool isBaseline = GetBool("isBaseline", obj);
879  int hoursPerYear = static_cast<int>(GetDouble("hoursPerYear", obj));
880  double electricityCost = GetDouble("electricityCost", obj);
881  double compressorPower = GetDouble("compressorPower", obj);
882  double pressure = GetDouble("pressure", obj);
883  double proposedPressure = GetDouble("proposedPressure", obj);
884  return {
885  isBaseline,
886  hoursPerYear,
887  electricityCost,
888  compressorPower,
889  pressure,
890  proposedPressure};
891 }
892 
893 std::vector<CompressedAirPressureReductionInput> getCompressedAirPressureReductionInputVec()
894 {
895  v8::Isolate *isolate = v8::Isolate::GetCurrent();
896  v8::Local<v8::Context> context = isolate->GetCurrentContext();
897  Local<String> getName = Nan::New<String>("compressedAirPressureReductionInputVec").ToLocalChecked();
898  Local<Value> arrayTmp = Nan::To<Object>(inp).ToLocalChecked()->Get(context, getName).ToLocalChecked();
899  if (arrayTmp->IsUndefined())
900  {
901  ThrowTypeError(std::string("CompressedAirPressureReduction: getCompressedAirPressureReductionInputVec method in calculator.h: compressedAirPressureReductionInputVec not present in object").c_str());
902  }
903  Local<Array> compressedAirPressureReductionInputArray = v8::Local<v8::Array>::Cast(arrayTmp);
904  std::vector<CompressedAirPressureReductionInput> inputVec;
905  for (std::size_t i = 0; i < compressedAirPressureReductionInputArray->Length(); i++)
906  {
907  inputVec.emplace_back(constructCompressedAirPressureReductionInput(Nan::To<Object>(compressedAirPressureReductionInputArray->Get(context, i).ToLocalChecked()).ToLocalChecked()));
908  }
909  return inputVec;
910 }
911 
912 NAN_METHOD(compressedAirPressureReduction)
913 {
914  inp = Nan::To<Object>(info[0]).ToLocalChecked();
915  r = Nan::New<Object>();
916  try
917  {
918  std::vector<CompressedAirPressureReductionInput> inputVec = getCompressedAirPressureReductionInputVec();
920  SetR("energyUse", rv.energyUse);
921  SetR("energyCost", rv.energyCost);
922  }
923  catch (std::runtime_error const &e)
924  {
925  std::string const what = e.what();
926  ThrowError(std::string("std::runtime_error thrown in compressedAirPressureReduction - calculator.h: " + what).c_str());
927  }
928  info.GetReturnValue().Set(r);
929 }
930 // ========== END CA Pressure Reduction ===========
931 
932 // ========== Start Pipe Insulation Reduction ===========
933 NAN_METHOD(pipeInsulationReduction)
934 {
935  inp = Nan::To<Object>(info[0]).ToLocalChecked();
936  r = Nan::New<Object>();
937 
938  int operatingHours = static_cast<int>(GetDouble("operatingHours", inp));
939  double pipeLength = GetDouble("pipeLength", inp);
940  double pipeDiameter = GetDouble("pipeDiameter", inp);
941  double pipeThickness = GetDouble("pipeThickness", inp);
942  double pipeTemperature = GetDouble("pipeTemperature", inp);
943  double ambientTemperature = GetDouble("ambientTemperature", inp);
944  double windVelocity = GetDouble("windVelocity", inp);
945  double systemEfficiency = Conversion(GetDouble("systemEfficiency", inp)).percentToFraction();
946  double insulationThickness = GetDouble("insulationThickness", inp);
947  double pipeEmissivity = GetDouble("pipeEmissivity", inp);
948  double jacketEmissivity = GetDouble("jacketEmissivity", inp);
949  std::vector<double> pipeMaterialCoefficients = GetVector("pipeMaterialCoefficients", inp);
950  std::vector<double> insulationMaterialCoefficients = GetVector("insulationMaterialCoefficients", inp);
951 
952  InsulatedPipeInput input(
953  operatingHours,
954  pipeLength,
955  pipeDiameter,
956  pipeThickness,
957  pipeTemperature,
958  ambientTemperature,
959  windVelocity,
960  systemEfficiency,
961  insulationThickness,
962  pipeEmissivity,
963  jacketEmissivity,
964  pipeMaterialCoefficients,
965  insulationMaterialCoefficients);
966  InsulatedPipeCalculator calculator(input);
967  InsulatedPipeOutput output = calculator.calculate();
968 
969  SetR("heatLength", output.getHeatLength());
970  SetR("annualHeatLoss", output.getAnnualHeatLoss());
971  info.GetReturnValue().Set(r);
972 }
973 // ========== END Pipe Insulation Reduction ===========
974 
975 // ========== Start Tank Insulation Reduction ===========
976 NAN_METHOD(tankInsulationReduction)
977 {
978  inp = Nan::To<Object>(info[0]).ToLocalChecked();
979  r = Nan::New<Object>();
980 
981  int operatingHours = static_cast<int>(GetDouble("operatingHours", inp));
982  double tankHeight = GetDouble("tankHeight", inp);
983  double tankDiameter = GetDouble("tankDiameter", inp);
984  double tankThickness = GetDouble("tankThickness", inp);
985  double tankEmissivity = GetDouble("tankEmissivity", inp);
986  double tankConductivity = GetDouble("tankConductivity", inp);
987  double tankTemperature = GetDouble("tankTemperature", inp);
988  double ambientTemperature = GetDouble("ambientTemperature", inp);
989  double systemEfficiency = Conversion(GetDouble("systemEfficiency", inp)).percentToFraction();
990  double insulationThickness = GetDouble("insulationThickness", inp);
991  double insulationConductivity = GetDouble("insulationConductivity", inp);
992  double jacketEmissivity = GetDouble("jacketEmissivity", inp);
993 
994  InsulatedTankInput input(
995  operatingHours,
996  tankHeight,
997  tankDiameter,
998  tankThickness,
999  tankEmissivity,
1000  tankConductivity,
1001  tankTemperature,
1002  ambientTemperature,
1003  systemEfficiency,
1004  insulationThickness,
1005  insulationConductivity,
1006  jacketEmissivity);
1007  InsulatedTankCalculator calculator(input);
1008  InsulatedTankOutput output = calculator.calculate();
1009 
1010  SetR("heatLoss", output.getHeatLoss());
1011  SetR("annualHeatLoss", output.getAnnualHeatLoss());
1012  info.GetReturnValue().Set(r);
1013 }
1014 // ========== END Tank Insulation Reduction ===========
1015 
1016 // ============ Start Steam Reduction =============
1017 SteamFlowMeterMethodData getSteamFlowMeterMethodData(Local<Object> obj)
1018 {
1019  v8::Isolate *isolate = v8::Isolate::GetCurrent();
1020  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1021  Local<String> getName = Nan::New<String>("flowMeterMethodData").ToLocalChecked();
1022  Local<Object> flowMeterMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
1023  if (flowMeterMethodDataV8->IsUndefined())
1024  {
1025  ThrowTypeError(std::string("SteamReduction: getSteamFlowMeterMethodData method in calculator.h: flowMeterMethodData not present in object").c_str());
1026  }
1027  double flowRate = GetDouble("flowRate", flowMeterMethodDataV8);
1028  return {flowRate};
1029 }
1030 
1031 SteamMassFlowMeasuredData getSteamMassFlowMeasuredData(Local<Object> obj)
1032 {
1033  v8::Isolate *isolate = v8::Isolate::GetCurrent();
1034  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1035  Local<String> getName = Nan::New<String>("massFlowMeasuredData").ToLocalChecked();
1036  Local<Object> massFlowMeasuredDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
1037  if (massFlowMeasuredDataV8->IsUndefined())
1038  {
1039  ThrowTypeError(std::string("SteamReduction: getSteamMassFlowMeasuredData method in calculator.h: massFlowMeasuredData not present in object").c_str());
1040  }
1041  double areaOfDuct = GetDouble("areaOfDuct", massFlowMeasuredDataV8);
1042  double airVelocity = GetDouble("airVelocity", massFlowMeasuredDataV8);
1043  return {
1044  areaOfDuct,
1045  airVelocity};
1046 }
1047 
1048 SteamMassFlowNameplateData getSteamMassFlowNameplateData(Local<Object> obj)
1049 {
1050  v8::Isolate *isolate = v8::Isolate::GetCurrent();
1051  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1052  Local<String> getName = Nan::New<String>("massFlowNameplateData").ToLocalChecked();
1053  Local<Object> massFlowNameplateDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
1054  if (massFlowNameplateDataV8->IsUndefined())
1055  {
1056  ThrowTypeError(std::string("SteamReduction: getSteamMassFlowNameplateData method in calculator.h: massFlowNameplateData not present in object").c_str());
1057  }
1058  double flowRate = GetDouble("flowRate", massFlowNameplateDataV8);
1059  return {flowRate};
1060 }
1061 
1062 SteamMassFlowMethodData getSteamAirMassFlowMethodData(Local<Object> obj)
1063 {
1064  v8::Isolate *isolate = v8::Isolate::GetCurrent();
1065  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1066  Local<String> getName = Nan::New<String>("airMassFlowMethodData").ToLocalChecked();
1067  Local<Object> massFlowMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
1068  if (massFlowMethodDataV8->IsUndefined())
1069  {
1070  ThrowTypeError(std::string("SteamReduction: getSteamAirMassFlowMethodData method in calculator.h: airMassFlowMethodData not present in object").c_str());
1071  }
1072  bool isNameplate = GetBool("isNameplate", massFlowMethodDataV8);
1073  SteamMassFlowMeasuredData measuredData = getSteamMassFlowMeasuredData(massFlowMethodDataV8);
1074  SteamMassFlowNameplateData nameplateData = getSteamMassFlowNameplateData(massFlowMethodDataV8);
1075  double inletTemperature = GetDouble("inletTemperature", massFlowMethodDataV8);
1076  double outletTemperature = GetDouble("outletTemperature", massFlowMethodDataV8);
1077  return {
1078  isNameplate,
1079  measuredData,
1080  nameplateData,
1081  inletTemperature,
1082  outletTemperature};
1083 }
1084 
1085 SteamMassFlowMethodData getSteamWaterMassFlowMethodData(Local<Object> obj)
1086 {
1087  v8::Isolate *isolate = v8::Isolate::GetCurrent();
1088  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1089  Local<String> getName = Nan::New<String>("waterMassFlowMethodData").ToLocalChecked();
1090  Local<Object> massFlowMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
1091  if (massFlowMethodDataV8->IsUndefined())
1092  {
1093  ThrowTypeError(std::string("SteamReduction: getSteamWaterMassFlowMethodData method in calculator.h: waterMassFlowMethodData not present in object").c_str());
1094  }
1095  bool isNameplate = GetBool("isNameplate", massFlowMethodDataV8);
1096  SteamMassFlowMeasuredData measuredData = getSteamMassFlowMeasuredData(massFlowMethodDataV8);
1097  SteamMassFlowNameplateData nameplateData = getSteamMassFlowNameplateData(massFlowMethodDataV8);
1098  double inletTemperature = GetDouble("inletTemperature", massFlowMethodDataV8);
1099  double outletTemperature = GetDouble("outletTemperature", massFlowMethodDataV8);
1100  return {
1101  isNameplate,
1102  measuredData,
1103  nameplateData,
1104  inletTemperature,
1105  outletTemperature};
1106 }
1107 
1108 SteamOtherMethodData getSteamOtherMethodData(Local<Object> obj)
1109 {
1110  v8::Isolate *isolate = v8::Isolate::GetCurrent();
1111  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1112  Local<String> getName = Nan::New<String>("otherMethodData").ToLocalChecked();
1113  Local<Object> otherMethodDataV8 = Nan::To<Object>(obj->Get(context, getName).ToLocalChecked()).ToLocalChecked();
1114  if (otherMethodDataV8->IsUndefined())
1115  {
1116  ThrowTypeError(std::string("SteamReduction: getSteamOtherMethodData method in calculator.h: otherMethodData not present in object").c_str());
1117  }
1118  double consumption = GetDouble("consumption", otherMethodDataV8);
1119  return {consumption};
1120 }
1121 
1122 SteamReductionInput constructSteamReductionInput(Local<Object> obj)
1123 {
1124  int hoursPerYear = static_cast<int>(GetDouble("hoursPerYear", obj));
1125  int utilityType = static_cast<int>(GetDouble("utilityType", obj));
1126  double utilityCost = GetDouble("utilityCost", obj);
1127  int measurementMethod = static_cast<int>(GetDouble("measurementMethod", obj));
1128  double systemEfficiency = Conversion(GetDouble("systemEfficiency", obj)).percentToFraction();
1129  double pressure = GetDouble("pressure", obj);
1130  SteamFlowMeterMethodData steamFlowMeterMethodData = getSteamFlowMeterMethodData(obj);
1131  SteamMassFlowMethodData steamAirMassFlowMethodData = getSteamAirMassFlowMethodData(obj);
1132  SteamMassFlowMethodData steamWaterMassFlowMethodData = getSteamWaterMassFlowMethodData(obj);
1133  SteamOtherMethodData otherMethodData = getSteamOtherMethodData(obj);
1134  int units = static_cast<int>(GetDouble("units", obj));
1135  return {
1136  hoursPerYear,
1137  utilityType,
1138  utilityCost,
1139  measurementMethod,
1140  systemEfficiency,
1141  pressure,
1142  steamFlowMeterMethodData,
1143  steamAirMassFlowMethodData,
1144  steamWaterMassFlowMethodData,
1145  otherMethodData,
1146  units};
1147 }
1148 
1149 std::vector<SteamReductionInput> getSteamReductionInputVec()
1150 {
1151  v8::Isolate *isolate = v8::Isolate::GetCurrent();
1152  v8::Local<v8::Context> context = isolate->GetCurrentContext();
1153  Local<String> getName = Nan::New<String>("steamReductionInputVec").ToLocalChecked();
1154  Local<Value> arrayTmp = Nan::To<Object>(inp).ToLocalChecked()->Get(context, getName).ToLocalChecked();
1155  if (arrayTmp->IsUndefined())
1156  {
1157  ThrowTypeError(std::string("SteamReduction: getSteamReductionInputVec method in calculator.h: steamReductionInputVec not present in object").c_str());
1158  }
1159  Local<Array> steamReductionInputArray = v8::Local<v8::Array>::Cast(arrayTmp);
1160  std::vector<SteamReductionInput> inputVec;
1161  for (std::size_t i = 0; i < steamReductionInputArray->Length(); i++)
1162  {
1163  inputVec.emplace_back(constructSteamReductionInput(Nan::To<Object>(steamReductionInputArray->Get(context, i).ToLocalChecked()).ToLocalChecked()));
1164  }
1165  return inputVec;
1166 }
1167 
1168 NAN_METHOD(steamReduction)
1169 {
1170  inp = Nan::To<Object>(info[0]).ToLocalChecked();
1171  r = Nan::New<Object>();
1172  try
1173  {
1174  std::vector<SteamReductionInput> inputVec = getSteamReductionInputVec();
1175  SteamReduction::Output rv = SteamReduction(inputVec).calculate();
1176  SetR("steamUse", rv.steamUse);
1177  SetR("energyUse", rv.energyUse);
1178  SetR("energyCost", rv.energyCost);
1179  }
1180  catch (std::runtime_error const &e)
1181  {
1182  std::string const what = e.what();
1183  ThrowError(std::string("std::runtime_error thrown in steamReduction - calculator.h: " + what).c_str());
1184  }
1185  info.GetReturnValue().Set(r);
1186 }
1187 // ============ END Steam Reduction =============