CoolProp  6.6.0
An open-source fluid property and humid air property database
IncompressibleBackend.cpp
Go to the documentation of this file.
1 
2 #if defined(_MSC_VER)
3 # define _CRTDBG_MAP_ALLOC
4 # ifndef _CRT_SECURE_NO_WARNINGS
5 # define _CRT_SECURE_NO_WARNINGS
6 # endif
7 # include <crtdbg.h>
8 # include <sys/stat.h>
9 #else
10 # include <sys/stat.h>
11 #endif
12 
13 #include <string>
14 //#include "CoolProp.h"
15 
16 #include "IncompressibleBackend.h"
17 #include "IncompressibleFluid.h"
18 #include "IncompressibleLibrary.h"
19 #include "DataStructures.h"
20 #include "Solvers.h"
21 #include "MatrixMath.h"
22 
23 namespace CoolProp {
24 
26  throw NotImplementedError("Empty constructor is not implemented for incompressible fluids");
27  //this->fluid = NULL;
28 }
29 
31  this->fluid = fluid;
32  this->set_reference_state();
33  if (this->fluid->is_pure()) {
34  this->set_fractions(std::vector<CoolPropDbl>(1, 1.0));
35  } else {
36  this->set_fractions(std::vector<CoolPropDbl>(1, 0.0));
37  }
38  //} else if (ValidNumber(this->fluid->xmin)) {
39  // this->set_fractions(std::vector<CoolPropDbl>(1,this->fluid->getxmin()));
40  //} else if (ValidNumber(this->fluid->xmax)) {
41  // this->set_fractions(std::vector<CoolPropDbl>(1,this->fluid->getxmax()));
42  //}
43 }
44 
45 IncompressibleBackend::IncompressibleBackend(const std::string& fluid_name) {
46  this->fluid = &get_incompressible_fluid(fluid_name);
47  this->set_reference_state();
48  if (this->fluid->is_pure()) {
49  this->set_fractions(std::vector<CoolPropDbl>(1, 1.0));
50  } else {
51  this->set_fractions(std::vector<CoolPropDbl>(1, 0.0));
52  }
53 }
54 
55 IncompressibleBackend::IncompressibleBackend(const std::vector<std::string>& component_names) {
56  throw NotImplementedError("Mixture-style constructor is not implemented yet for incompressible fluids");
57 }
58 
59 void IncompressibleBackend::update(CoolProp::input_pairs input_pair, double value1, double value2) {
60  //if (mass_fractions.empty()){
61  // throw ValueError("mass fractions have not been set");
62  //}
63 
64  if (get_debug_level() >= 10) {
65  //throw ValueError(format("%s (%d): You have to provide a dimension, 0 or 1, for the solver, %d is not valid. ",__FILE__,__LINE__,axis));
66  std::cout << format("Incompressible backend: Called update with %d and %f, %f ", input_pair, value1, value2) << std::endl;
67  }
68 
69  clear();
70 
71  if (get_debug_level() >= 50) {
72  std::cout << format("Incompressible backend: _fractions are %s ", vec_to_string(_fractions).c_str()) << std::endl;
73  }
74  if (_fractions.size() != 1) {
75  throw ValueError(format("%s is an incompressible fluid, mass fractions must be set to a vector with ONE entry, not %d.", this->name().c_str(),
76  _fractions.size()));
77  }
78  if (fluid->is_pure()) {
80  if (get_debug_level() >= 50) std::cout << format("Incompressible backend: Fluid type is %d ", this->_fluid_type) << std::endl;
81  if (_fractions[0] != 1.0) {
82  throw ValueError(format("%s is a pure fluid. The composition has to be set to a vector with one entry equal to 1.0. %s is not valid.",
83  this->name().c_str(), vec_to_string(_fractions).c_str()));
84  }
85  } else {
87  if (get_debug_level() >= 50) std::cout << format("Incompressible backend: Fluid type is %d ", this->_fluid_type) << std::endl;
88  if ((_fractions[0] < 0.0) || (_fractions[0] > 1.0)) {
89  throw ValueError(
90  format("%s is a solution or brine. Mass fractions must be set to a vector with one entry between 0 and 1. %s is not valid.",
91  this->name().c_str(), vec_to_string(_fractions).c_str()));
92  }
93  }
94 
95  this->_phase = iphase_liquid;
96  if (get_debug_level() >= 50) std::cout << format("Incompressible backend: Phase type is %d ", this->_phase) << std::endl;
97 
98  switch (input_pair) {
99  case PT_INPUTS: {
100  _p = value1;
101  _T = value2;
102  break;
103  }
104  case DmassP_INPUTS: {
105  _p = value2;
106  _T = this->DmassP_flash(value1, value2);
107  break;
108  }
109  // case PUmass_INPUTS: {
110  // _p = value1;
111  // _T = this->PUmass_flash(value1, value2);
112  // break;
113  // }
114  case PSmass_INPUTS: {
115  _p = value1;
116  _T = this->PSmass_flash(value1, value2);
117  break;
118  }
119  case HmassP_INPUTS: {
120  _p = value2;
121  _T = this->HmassP_flash(value1, value2);
122  break;
123  }
124  case QT_INPUTS: {
125  if (value1 != 0) {
126  throw ValueError("Incompressible fluids can only handle saturated liquid, Q=0.");
127  }
128  _T = value2;
129  _p = fluid->psat(value2, _fractions[0]);
130  break;
131  }
132  default: {
133  throw ValueError(format("This pair of inputs [%s] is not yet supported", get_input_pair_short_desc(input_pair).c_str()));
134  }
135  }
136  if (_p < 0) {
137  throw ValueError("p is less than zero");
138  }
139  if (!ValidNumber(_p)) {
140  throw ValueError("p is not a valid number");
141  }
142  if (_T < 0) {
143  throw ValueError("T is less than zero");
144  }
145  if (!ValidNumber(_T)) {
146  throw ValueError("T is not a valid number");
147  }
148  if (get_debug_level() >= 50)
149  std::cout << format("Incompressible backend: Update finished T=%f, p=%f, x=%s ", this->_T, this->_p, vec_to_string(_fractions).c_str())
150  << std::endl;
151  fluid->checkTPX(_T, _p, _fractions[0]);
152 }
153 
156  AbstractState::clear(); // Call the base class
158  this->_cmass.clear();
159  this->_hmass.clear();
160  this->_rhomass.clear();
161  this->_smass.clear();
162  this->_umass.clear();
163 
164  this->_drhodTatPx.clear();
165  this->_dsdTatPx.clear();
166  this->_dhdTatPx.clear();
167  this->_dsdTatPxdT.clear();
168  this->_dhdTatPxdT.clear();
169  this->_dsdpatTx.clear();
170  this->_dhdpatTx.clear();
171  // Done
172  return true;
173 }
174 
176 void IncompressibleBackend::set_reference_state(double T0, double p0, double x0, double h0, double s0) {
177  this->clear();
179  this->_hmass_ref.clear();
180  this->_smass_ref.clear();
181  //
182  this->_T_ref = T0;
183  this->_p_ref = p0;
184  this->_x_ref = x0;
185  this->_h_ref = h0;
186  this->_s_ref = s0;
187 }
188 
190 
193 void IncompressibleBackend::set_fractions(const std::vector<CoolPropDbl>& fractions) {
194  if (get_debug_level() >= 10)
195  std::cout << format("Incompressible backend: Called set_fractions with %s ", vec_to_string(fractions).c_str()) << std::endl;
196  if (fractions.size() != 1)
197  throw ValueError(format("The incompressible backend only supports one entry in the fraction vector and not %d.", fractions.size()));
198  if ((this->_fractions.size() != 1) || (this->_fractions[0] != fractions[0])) { // Change it!
199  if (get_debug_level() >= 20)
200  std::cout << format("Incompressible backend: Updating the fractions triggered a change in reference state %s -> %s",
201  vec_to_string(this->_fractions).c_str(), vec_to_string(fractions).c_str())
202  << std::endl;
203  this->_fractions = fractions;
204  set_reference_state(T_ref(), p_ref(), this->_fractions[0], h_ref(), s_ref());
205  }
206 }
207 
209 
212 void IncompressibleBackend::set_mole_fractions(const std::vector<CoolPropDbl>& mole_fractions) {
213  if (get_debug_level() >= 10)
214  std::cout << format("Incompressible backend: Called set_mole_fractions with %s ", vec_to_string(mole_fractions).c_str()) << std::endl;
215  if (mole_fractions.size() != 1)
216  throw ValueError(format("The incompressible backend only supports one entry in the mole fraction vector and not %d.", mole_fractions.size()));
217  if ((fluid->getxid() == IFRAC_PURE) && true) { //( this->_fractions[0]!=1.0 )){
218  this->set_fractions(std::vector<CoolPropDbl>(1, 1.0));
219  if (get_debug_level() >= 20)
220  std::cout << format("Incompressible backend: Overwriting fractions for pure fluid with %s -> %s", vec_to_string(mole_fractions).c_str(),
221  vec_to_string(this->_fractions).c_str())
222  << std::endl;
223  } else if (fluid->getxid() == IFRAC_MOLE) {
224  this->set_fractions(mole_fractions);
225  } else {
226  std::vector<CoolPropDbl> tmp_fractions;
227  for (std::size_t i = 0; i < mole_fractions.size(); i++) {
228  tmp_fractions.push_back((CoolPropDbl)fluid->inputFromMole(0.0, mole_fractions[i]));
229  }
230  this->set_fractions(tmp_fractions);
231  }
232 }
233 
235 
238 void IncompressibleBackend::set_mass_fractions(const std::vector<CoolPropDbl>& mass_fractions) {
239  if (get_debug_level() >= 10)
240  std::cout << format("Incompressible backend: Called set_mass_fractions with %s ", vec_to_string(mass_fractions).c_str()) << std::endl;
241  if (mass_fractions.size() != 1)
242  throw ValueError(format("The incompressible backend only supports one entry in the mass fraction vector and not %d.", mass_fractions.size()));
243  if ((fluid->getxid() == IFRAC_PURE) && true) { // ( this->_fractions[0]!=1.0 )) {
244  this->set_fractions(std::vector<CoolPropDbl>(1, 1.0));
245  if (get_debug_level() >= 20)
246  std::cout << format("Incompressible backend: Overwriting fractions for pure fluid with %s -> %s", vec_to_string(mass_fractions).c_str(),
247  vec_to_string(this->_fractions).c_str())
248  << std::endl;
249  } else if (fluid->getxid() == IFRAC_MASS) {
250  this->set_fractions(mass_fractions);
251  } else {
252  std::vector<CoolPropDbl> tmp_fractions;
253  for (std::size_t i = 0; i < mass_fractions.size(); i++) {
254  tmp_fractions.push_back((CoolPropDbl)fluid->inputFromMass(0.0, mass_fractions[i]));
255  }
256  this->set_fractions(tmp_fractions);
257  }
258 }
259 
261 
264 void IncompressibleBackend::set_volu_fractions(const std::vector<CoolPropDbl>& volu_fractions) {
265  if (get_debug_level() >= 10)
266  std::cout << format("Incompressible backend: Called set_volu_fractions with %s ", vec_to_string(volu_fractions).c_str()) << std::endl;
267  if (volu_fractions.size() != 1)
268  throw ValueError(
269  format("The incompressible backend only supports one entry in the volume fraction vector and not %d.", volu_fractions.size()));
270  if ((fluid->getxid() == IFRAC_PURE) && true) { // ( this->_fractions[0]!=1.0 )) {
271  this->set_fractions(std::vector<CoolPropDbl>(1, 1.0));
272  if (get_debug_level() >= 20)
273  std::cout << format("Incompressible backend: Overwriting fractions for pure fluid with %s -> %s", vec_to_string(volu_fractions).c_str(),
274  vec_to_string(this->_fractions).c_str())
275  << std::endl;
276  } else if (fluid->getxid() == IFRAC_VOLUME) {
277  this->set_fractions(volu_fractions);
278  } else {
279  std::vector<CoolPropDbl> tmp_fractions;
280  for (std::size_t i = 0; i < volu_fractions.size(); i++) {
281  tmp_fractions.push_back((CoolPropDbl)fluid->inputFromVolume(0.0, volu_fractions[i]));
282  }
283  this->set_fractions(tmp_fractions);
284  }
285 }
286 
289  throw NotImplementedError("Cannot check status for incompressible fluid");
290 }
291 
299  if (!_rhomass) _rhomass = calc_rhomass();
300  return _rhomass;
301 }
304  if (!_hmass) _hmass = calc_hmass();
305  return _hmass;
306 }
309  if (!_smass) _smass = calc_smass();
310  return _smass;
311 }
314  if (!_umass) _umass = calc_umass();
315  return _umass;
316 }
319  if (!_cmass) _cmass = calc_cmass();
320  return _cmass;
321 }
322 
325  return _drhodTatPx;
326 }
329  return _dsdTatPx;
330 }
333  return _dhdTatPx;
334 }
337  return _dsdTatPxdT;
338 }
341  return _dhdTatPxdT;
342 }
345  return _dsdpatTx;
346 }
349  return _dhdpatTx;
350 }
351 
354  if (!_T_ref) throw ValueError("Reference temperature is not set");
355  return _T_ref;
356 }
359  if (!_p_ref) throw ValueError("Reference pressure is not set");
360  return _p_ref;
361 }
364  if (!_x_ref) throw ValueError("Reference composition is not set");
365  return _x_ref;
366 }
369  if (!_h_ref) throw ValueError("Reference enthalpy is not set");
370  return _h_ref;
371 }
374  if (!_s_ref) throw ValueError("Reference entropy is not set");
375  return _s_ref;
376 }
377 
381  return _hmass_ref;
382 }
386  return _smass_ref;
387 }
388 
390 
396  return fluid->T_rho(rhomass, p, _fractions[0]);
397 }
399 
405 
406  class HmassP_residual : public FuncWrapper1D
407  {
408  protected:
409  double p, x, h_in;
410  IncompressibleBackend* backend;
411 
412  public:
413  HmassP_residual(IncompressibleBackend* backend, const double& p, const double& x, const double& h_in)
414  : p(p), x(x), h_in(h_in), backend(backend) {}
415  double call(double target) {
416  return backend->raw_calc_hmass(target, p, x) - h_in; //fluid.u(target,p,x)+ p / fluid.rho(target,p,x) - h_in;
417  }
418  //double deriv(double target);
419  };
420 
421  HmassP_residual res = HmassP_residual(this, p, _fractions[0], hmass - h_ref() + hmass_ref());
422 
423  double macheps = DBL_EPSILON;
424  double tol = DBL_EPSILON * 1e3;
425  int maxiter = 10;
426  double result = Brent(&res, fluid->getTmin(), fluid->getTmax(), macheps, tol, maxiter);
427  //if (this->do_debug()) std::cout << "Brent solver message: " << errstring << std::endl;
428  return result;
429 }
431 
437 
438  class PSmass_residual : public FuncWrapper1D
439  {
440  protected:
441  double p, x, s_in;
442  IncompressibleBackend* backend;
443 
444  public:
445  PSmass_residual(IncompressibleBackend* backend, const double& p, const double& x, const double& s_in)
446  : p(p), x(x), s_in(s_in), backend(backend) {}
447  double call(double target) {
448  return backend->raw_calc_smass(target, p, x) - s_in;
449  }
450  };
451 
452  PSmass_residual res = PSmass_residual(this, p, _fractions[0], smass - s_ref() + smass_ref());
453 
454  double macheps = DBL_EPSILON;
455  double tol = DBL_EPSILON * 1e3;
456  int maxiter = 10;
457  double result = Brent(&res, fluid->getTmin(), fluid->getTmax(), macheps, tol, maxiter);
458  //if (this->do_debug()) std::cout << "Brent solver message: " << errstring << std::endl;
459  return result;
460 }
461 
464 //@param umass The mass internal energy in J/kg
465 //@param p The pressure in Pa
466 //@returns T The temperature in K
467 //*/
468 //CoolPropDbl IncompressibleBackend::PUmass_flash(CoolPropDbl p, CoolPropDbl umass){
469 //
470 // class PUmass_residual : public FuncWrapper1D {
471 // protected:
472 // double p,x,u_in;
473 // IncompressibleBackend* fluid;
474 // protected:
475 // PUmass_residual(){};
476 // public:
477 // PUmass_residual(IncompressibleBackend* fluid, const double &p, const double &x, const double &u_in){
478 // this->p = p;
479 // this->x = x;
480 // this->u_in = u_in;
481 // this->fluid = fluid;
482 // }
483 // virtual ~PUmass_residual(){};
484 // double call(double target){
485 // return fluid->u(target,p,x) - u_in;
486 // }
487 // };
488 //
489 // PUmass_residual res = PUmass_residual(*this, p, _fractions[0], umass);
490 //
491 // std::string errstring;
492 // double macheps = DBL_EPSILON;
493 // double tol = DBL_EPSILON*1e3;
494 // int maxiter = 10;
495 // double result = Brent(&res, fluid->getTmin(), fluid->getTmax(), macheps, tol, maxiter, errstring);
496 // //if (this->do_debug()) std::cout << "Brent solver message: " << errstring << std::endl;
497 // return result;
498 //}
499 
502  if (param == iT && given == iP) {
503  return fluid->Tfreeze(value, _fractions[0]);
504  } else {
505  throw ValueError("For incompressibles, the only valid inputs to calc_melting_line are T(p)");
506  }
507 };
509  return hmass() - _p / rhomass();
510 };
511 
514  return h_ref() + raw_calc_hmass(_T, _p, _fractions[0]) - hmass_ref();
515 };
517  return s_ref() + raw_calc_smass(_T, _p, _fractions[0]) - smass_ref();
518 };
519 
521 CoolPropDbl IncompressibleBackend::raw_calc_hmass(double T, double p, double x) {
522  return calc_dhdTatPxdT(T, p, x) + p * calc_dhdpatTx(T, fluid->rho(T, p, x), calc_drhodTatPx(T, p, x));
523 };
524 CoolPropDbl IncompressibleBackend::raw_calc_smass(double T, double p, double x) {
525  return calc_dsdTatPxdT(T, p, x) + p * calc_dsdpatTx(fluid->rho(T, p, x), calc_drhodTatPx(T, p, x));
526 };
527 
530  // TODO: Can this be accelerated?
531  if ((Of == iDmass) && (Wrt == iP)) return 0.0; // incompressible!
532  if ((Of == iDmass) && (Wrt == iHmass) && (Constant == iP)) return drhodTatPx() / dhdTatPx();
533  if ((Of == iHmass) && (Wrt == iDmass) && (Constant == iP)) return dhdTatPx() / drhodTatPx();
534  if ((Of == iDmass) && (Wrt == iSmass) && (Constant == iP)) return drhodTatPx() / dsdTatPx();
535  if ((Of == iSmass) && (Wrt == iDmass) && (Constant == iP)) return dsdTatPx() / drhodTatPx();
536  if ((Of == iDmass) && (Wrt == iT) && (Constant == iP)) return drhodTatPx();
537  if ((Of == iT) && (Wrt == iDmass) && (Constant == iP)) return 1.0 / drhodTatPx();
538  //
539  if ((Of == iHmass) && (Wrt == iP) && (Constant == iT)) return dhdpatTx();
540  if ((Of == iP) && (Wrt == iHmass) && (Constant == iT)) return 1.0 / dhdpatTx();
541  if ((Of == iHmass) && (Wrt == iSmass) && (Constant == iT)) return dhdpatTx() / dsdpatTx();
542  if ((Of == iSmass) && (Wrt == iHmass) && (Constant == iT)) return dsdpatTx() / dhdpatTx();
543  if ((Of == iHmass) && (Wrt == iT) && (Constant == iP)) return dhdTatPx();
544  if ((Of == iT) && (Wrt == iHmass) && (Constant == iP)) return 1.0 / dhdTatPx();
545  //
546  if ((Of == iSmass) && (Wrt == iP) && (Constant == iT)) return dsdpatTx();
547  if ((Of == iP) && (Wrt == iSmass) && (Constant == iT)) return 1.0 / dsdpatTx();
548  if ((Of == iSmass) && (Wrt == iT) && (Constant == iP)) return dsdTatPx();
549  if ((Of == iT) && (Wrt == iSmass) && (Constant == iP)) return 1.0 / dsdTatPx();
550  //if ( (Of==iHmass) && (Wrt==iP) && (Constant==iT) ) return dsdTatPxdT();
551  //if ( (Of==iHmass) && (Wrt==iP) && (Constant==iT) ) return dhdTatPxdT();
552  throw ValueError("Incompressible fluids only support a limited subset of partial derivatives.");
553 }
554 
555 /* Other useful derivatives
556  */
558 // \f[ \left( \frac{\partial s}{\partial p} \right)_T = - \left( \frac{\partial v}{\partial T} \right)_p = \rho^{-2} \left( \frac{\partial \rho}{\partial T} \right)_p \right) \f]
559 double IncompressibleBackend::calc_dsdpatTx(double rho, double drhodTatPx) {
560  return 1 / rho / rho * drhodTatPx;
561 }
563 // \f[ \left( \frac{\partial h}{\partial p} \right)_T = v - T \left( \frac{\partial v}{\partial T} \right)_p = \rho^{-1} \left( 1 + T \rho^{-1} \left( \frac{\partial \rho}{\partial T} \right)_p \right) \f]
564 double IncompressibleBackend::calc_dhdpatTx(double T, double rho, double drhodTatPx) {
565  return 1 / rho * (1 + T / rho * drhodTatPx);
566 }
567 
568 } // namespace CoolProp
569 
570 // Testing routines with fixed parameters and known results
571 /* These functions try to cover as much as possible, but
572  * they still need some serious additions.
573  */
574 
575 #ifdef ENABLE_CATCH
576 # include <math.h>
577 # include <iostream>
578 # include <catch2/catch_all.hpp>
579 
580 # include "TestObjects.h"
581 
582 TEST_CASE("Internal consistency checks and example use cases for the incompressible backend", "[IncompressibleBackend]") {
585 
586  SECTION("Test case for Methanol from SecCool") {
587 
588  // Some basic functions
589  // has to return false
590  CHECK(backend.using_mole_fractions() == false);
591 
592  //void update(long input_pair, double value1, double value2);
593 
594  std::vector<CoolPropDbl> fractions;
595  fractions.push_back(0.4);
596  CHECK_THROWS(backend.set_mole_fractions(fractions));
597  CHECK_NOTHROW(backend.set_mass_fractions(fractions));
598  fractions.push_back(0.4);
599  CHECK_THROWS(backend.set_mass_fractions(fractions));
600  CHECK_THROWS(backend.check_status());
601 
602  // Prepare the results and compare them to the calculated values
603  double acc = 0.0001;
604  double T = 273.15 + 10;
605  double p = 10e5;
606  double x = 0.25;
607  backend.set_mass_fractions(std::vector<CoolPropDbl>(1, x));
608  double val = 0;
609  double res = 0;
610 
611  //CoolProp::set_debug_level(100);
612 
613  // Compare density flash
614  val = fluid.rho(T, p, x);
615  res = backend.DmassP_flash(val, p);
616  {
617  CAPTURE(T);
618  CAPTURE(p);
619  CAPTURE(x);
620  CAPTURE(val);
621  CAPTURE(res);
622  CHECK(check_abs(T, res, acc));
623  }
624 
625  // call the update function to set internal variables,
626  // concentration has been set before.
627  CHECK_THROWS(backend.update(CoolProp::DmassT_INPUTS, val, T)); // First with wrong parameters
628  CHECK_NOTHROW(backend.update(CoolProp::PT_INPUTS, p, T)); // ... and then with the correct ones.
629 
630  // Compare enthalpy flash
631  val = backend.hmass();
632  res = backend.HmassP_flash(val, p);
633  {
634  CAPTURE(T);
635  CAPTURE(p);
636  CAPTURE(x);
637  CAPTURE(val);
638  CAPTURE(res);
639  CHECK(check_abs(T, res, acc));
640  }
641 
642  // Compare entropy flash
643  val = backend.smass();
644  res = backend.PSmass_flash(p, val);
645  {
646  CAPTURE(T);
647  CAPTURE(p);
648  CAPTURE(x);
649  CAPTURE(val);
650  CAPTURE(res);
651  CHECK(check_abs(T, res, acc));
652  }
653 
655  val = fluid.visc(T, p, x);
656  res = backend.calc_viscosity();
657  {
658  CAPTURE(T);
659  CAPTURE(p);
660  CAPTURE(x);
661  CAPTURE(val);
662  CAPTURE(res);
663  CHECK(check_abs(val, res, acc));
664  }
665 
667  val = fluid.cond(T, p, x);
668  res = backend.calc_conductivity();
669  {
670  CAPTURE(T);
671  CAPTURE(p);
672  CAPTURE(x);
673  CAPTURE(val);
674  CAPTURE(res);
675  CHECK(check_abs(val, res, acc));
676  }
677 
678  val = fluid.rho(T, p, x);
679  res = backend.rhomass();
680  {
681  CAPTURE(T);
682  CAPTURE(p);
683  CAPTURE(x);
684  CAPTURE(val);
685  CAPTURE(res);
686  CHECK(check_abs(val, res, acc));
687  }
688 
689  // val = fluid.h(T, p, x);
690  // res = backend.hmass();
691  // {
692  // CAPTURE(T);
693  // CAPTURE(p);
694  // CAPTURE(x);
695  // CAPTURE(val);
696  // CAPTURE(res);
697  // CHECK( check_abs(val,res,acc) );
698  // }
699  //
700  // val = fluid.s(T, p, x);
701  // res = backend.smass();
702  // {
703  // CAPTURE(T);
704  // CAPTURE(p);
705  // CAPTURE(x);
706  // CAPTURE(val);
707  // CAPTURE(res);
708  // CHECK( check_abs(val,res,acc) );
709  // }
710  // Make sure the result does not change -> reference state...
711  val = backend.smass();
712  backend.update(CoolProp::PT_INPUTS, p, T);
713  res = backend.smass();
714  {
715  CAPTURE(T);
716  CAPTURE(p);
717  CAPTURE(x);
718  CAPTURE(val);
719  CAPTURE(res);
720  CHECK(check_abs(val, res, acc));
721  }
722 
723  val = fluid.c(T, p, x);
724  res = backend.cpmass();
725  {
726  CAPTURE(T);
727  CAPTURE(p);
728  CAPTURE(x);
729  CAPTURE(val);
730  CAPTURE(res);
731  CHECK(check_abs(val, res, acc));
732  }
733 
734  res = backend.cvmass();
735  {
736  CAPTURE(T);
737  CAPTURE(p);
738  CAPTURE(x);
739  CAPTURE(val);
740  CAPTURE(res);
741  CHECK(check_abs(val, res, acc));
742  }
743 
744  // Compare Tfreeze
745  val = fluid.Tfreeze(p, x); //-20.02+273.15;// 253.1293105454671;
746  res = backend.calc_T_freeze(); // -20.02+273.15;
747  {
748  CAPTURE(T);
749  CAPTURE(p);
750  CAPTURE(x);
751  CAPTURE(val);
752  CAPTURE(res);
753  CHECK(check_abs(val, res, acc));
754  }
755 
756  // Testing the reference state function
757  double Tref = 20 + 273.15 - 20;
758  double pref = 101325 * 10;
759  double xref = x;
760  backend.set_reference_state(Tref, pref, xref, 0.5, 0.5);
761  backend.set_mass_fractions(std::vector<CoolPropDbl>(1, x));
762  backend.update(CoolProp::PT_INPUTS, pref, Tref);
763  val = 0.5;
764  res = backend.hmass();
765  {
766  CAPTURE(Tref);
767  CAPTURE(pref);
768  CAPTURE(val);
769  CAPTURE(res);
770  CHECK(check_abs(val, res, acc));
771  }
772 
773  val = 0.5;
774  res = backend.smass();
775  {
776  CAPTURE(Tref);
777  CAPTURE(pref);
778  CAPTURE(val);
779  CAPTURE(res);
780  CHECK(check_abs(val, res, acc));
781  }
782 
783  backend.set_reference_state(Tref, pref, xref, 123, 456);
784  backend.update(CoolProp::PT_INPUTS, pref, Tref);
785  val = 123;
786  res = backend.hmass();
787  {
788  CAPTURE(Tref);
789  CAPTURE(pref);
790  CAPTURE(val);
791  CAPTURE(res);
792  CHECK(check_abs(val, res, acc));
793  }
794 
795  val = 456;
796  res = backend.smass();
797  {
798  CAPTURE(Tref);
799  CAPTURE(pref);
800  CAPTURE(val);
801  CAPTURE(res);
802  CHECK(check_abs(val, res, acc));
803  }
804 
805  backend.set_reference_state(Tref, pref, xref, 789, 123);
806  backend.update(CoolProp::PT_INPUTS, pref, Tref);
807  val = 789;
808  res = backend.hmass();
809  {
810  CAPTURE(Tref);
811  CAPTURE(pref);
812  CAPTURE(val);
813  CAPTURE(res);
814  CHECK(check_abs(val, res, acc));
815  }
816 
817  val = 123;
818  res = backend.smass();
819  {
820  CAPTURE(Tref);
821  CAPTURE(pref);
822  CAPTURE(val);
823  CAPTURE(res);
824  CHECK(check_abs(val, res, acc));
825  }
826  }
827 
828  SECTION("Tests for the full implementation using PropsSI") {
829 
830  // Prepare the results and compare them to the calculated values
831  std::string fluid("ExampleMelinder");
832  double acc = 0.0001;
833  double T = -5 + 273.15;
834  double p = 10e5;
835  double x = 0.3;
836  double expected = 0;
837  double actual = 0;
838 
839  // Compare different inputs
840  // ... as vector
841  expected = 9.6212e+02;
842  std::vector<std::string> fluid_Melinder(1, fluid);
843  std::vector<std::vector<double>> IO = CoolProp::PropsSImulti(std::vector<std::string>(1, "D"), "T", std::vector<double>(1, T), "P",
844  std::vector<double>(1, p), "INCOMP", fluid_Melinder, std::vector<double>(1, x));
845  REQUIRE(!IO.empty());
846  actual = IO[0][0];
847  {
848  CAPTURE(T);
849  CAPTURE(p);
850  CAPTURE(x);
851  CAPTURE(expected);
852  CAPTURE(actual);
853  CHECK(check_abs(expected, actual, acc));
854  }
855  // ... as %
856  actual = CoolProp::PropsSI("D", "T", T, "P", p, "INCOMP::" + fluid + format("-%f%%", x * 100.0));
857  {
858  CAPTURE(T);
859  CAPTURE(p);
860  CAPTURE(x);
861  CAPTURE(expected);
862  CAPTURE(actual);
863  std::string errmsg = CoolProp::get_global_param_string("errstring");
864  CAPTURE(errmsg);
865  CHECK(check_abs(expected, actual, acc));
866  }
867  // ... as mass fraction
868  actual = CoolProp::PropsSI("D", "T", T, "P", p, "INCOMP::" + fluid + format("[%f]", x));
869  {
870  CAPTURE(T);
871  CAPTURE(p);
872  CAPTURE(x);
873  CAPTURE(expected);
874  CAPTURE(actual);
875  std::string name = "INCOMP::" + fluid + format("[%f]", x);
876  CAPTURE(name);
877  std::string errmsg = CoolProp::get_global_param_string("errstring");
878  CAPTURE(errmsg);
879  CHECK(check_abs(expected, actual, acc));
880  }
881  // entropy reference state problems
882  //CoolProp::set_debug_level(51);
883  expected = CoolProp::PropsSI("S", "T", T, "P", p, "INCOMP::" + fluid + format("[%f]", x));
884  actual = CoolProp::PropsSI("S", "T", T, "P", p, "INCOMP::" + fluid + format("[%f]", x));
885  {
886  CAPTURE(T);
887  CAPTURE(p);
888  CAPTURE(x);
889  CAPTURE(expected);
890  CAPTURE(actual);
891  std::string name = "INCOMP::" + fluid + format("[%f]", x);
892  CAPTURE(name);
893  std::string errmsg = CoolProp::get_global_param_string("errstring");
894  CAPTURE(errmsg);
895  CHECK(check_abs(expected, actual, acc));
896  }
897  }
898  SECTION("SecCool example") {
899  double acc = 0.0001;
900  std::string backend = "INCOMP";
901  std::vector<std::string> fluids(1, "ExampleSecCool");
902  double T = -5 + 273.15;
903  double p = 10e5;
904  double x = 0.4;
905  std::vector<double> x_vec = std::vector<double>(1, x);
906  std::vector<double> T_vec = std::vector<double>(1, T);
907  std::vector<double> p_vec = std::vector<double>(1, p);
908 
909  // Compare d
910  double dexpected = 9.4844e+02;
911  std::vector<std::vector<double>> IO =
912  CoolProp::PropsSImulti(std::vector<std::string>(1, "D"), "T", T_vec, "P", p_vec, backend, fluids, x_vec);
913  REQUIRE(!IO.empty());
914  double dactual = IO[0][0];
915  {
916  CAPTURE(T);
917  CAPTURE(p);
918  CAPTURE(x);
919  CAPTURE(dexpected);
920  CAPTURE(dactual);
921  std::string errmsg = CoolProp::get_global_param_string("errstring");
922  CAPTURE(errmsg);
923  CHECK(check_abs(dexpected, dactual, acc));
924  }
925 
926  // Compare cp
927  double cpexpected = 3.6304e+03;
928  double cpactual = CoolProp::PropsSImulti(std::vector<std::string>(1, "C"), "T", T_vec, "P", p_vec, backend, fluids, x_vec)[0][0];
929  {
930  CAPTURE(T);
931  CAPTURE(p);
932  CAPTURE(x);
933  CAPTURE(cpexpected);
934  CAPTURE(cpactual);
935  std::string errmsg = CoolProp::get_global_param_string("errstring");
936  CAPTURE(errmsg);
937  CHECK(check_abs(cpexpected, cpactual, acc));
938  }
939  }
940  SECTION("INCOMP::ExamplePure") {
941  double acc = 0.0001;
942  std::string fluid = std::string("INCOMP::ExamplePure");
943  double T = +55 + 273.15;
944  double p = 10e5;
945 
946  // Compare d
947  double dexpected = 7.3646e+02;
948  double dactual = CoolProp::PropsSI("D", "T", T, "P", p, fluid);
949  {
950  CAPTURE(T);
951  CAPTURE(p);
952  CAPTURE(dexpected);
953  CAPTURE(dactual);
954  std::string errmsg = CoolProp::get_global_param_string("errstring");
955  CAPTURE(errmsg);
956  CHECK(check_abs(dexpected, dactual, acc));
957  }
958 
959  // Compare cp
960  double cpexpected = 2.2580e+03;
961  double cpactual = CoolProp::PropsSI("C", "T", T, "P", p, fluid);
962  {
963  CAPTURE(T);
964  CAPTURE(p);
965  CAPTURE(cpexpected);
966  CAPTURE(cpactual);
967  std::string errmsg = CoolProp::get_global_param_string("errstring");
968  CAPTURE(errmsg);
969  CHECK(check_abs(cpexpected, cpactual, acc));
970  }
971  }
972 
973  // SECTION("Tests for the hardcoded fluids") {
974  //
975  // // Prepare the results and compare them to the calculated values
976  // std::string fluid("INCOMP::LiBr");
977  // double acc = 0.0001;
978  // double T = 50 + 273.15;
979  // double p = 10e5;
980  // double x = 0.3;
981  // double val = 0;
982  // double res = 0;
983  //
984  // // Compare different inputs
985  // // ... as vector
986  // val = 9.6212e+02;
987  // res = CoolProp::PropsSI("D","T",T,"P",p,fluid,std::vector<double>(1,x));
988  // {
989  // CAPTURE(T);
990  // CAPTURE(p);
991  // CAPTURE(x);
992  // CAPTURE(val);
993  // CAPTURE(res);
994  // CHECK( check_abs(val,res,acc) );
995  // }
996  // // ... as %
997  // res = CoolProp::PropsSI("D","T",T,"P",p,fluid+format("-%f%s",x*100.0,"%"));
998  // {
999  // CAPTURE(T);
1000  // CAPTURE(p);
1001  // CAPTURE(x);
1002  // CAPTURE(val);
1003  // CAPTURE(res);
1004  // CHECK( check_abs(val,res,acc) );
1005  // }
1006  // // ... as mass fraction
1007  // res = CoolProp::PropsSI("D","T",T,"P",p,fluid+format("[%f]",x));
1008  // {
1009  // CAPTURE(T);
1010  // CAPTURE(p);
1011  // CAPTURE(x);
1012  // CAPTURE(val);
1013  // CAPTURE(res);
1014  // CHECK( check_abs(val,res,acc) );
1015  // }
1016  //
1017  //
1018  // fluid = std::string("INCOMP::ExampleSecCool");
1019  // T = -5 + 273.15;
1020  // p = 10e5;
1021  // x = 0.4;
1022  // std::vector<double> x_vec = std::vector<double>(1,x);
1023  //
1024  // // Compare d
1025  // val = 9.4844e+02;
1026  // res = CoolProp::PropsSI("D","T",T,"P",p,fluid,x_vec);
1027  // {
1028  // CAPTURE(T);
1029  // CAPTURE(p);
1030  // CAPTURE(x);
1031  // CAPTURE(val);
1032  // CAPTURE(res);
1033  // CHECK( check_abs(val,res,acc) );
1034  // }
1035  //
1036  // // Compare cp
1037  // val = 3.6304e+03;
1038  // res = CoolProp::PropsSI("C","T",T,"P",p,fluid,x_vec);
1039  // {
1040  // CAPTURE(T);
1041  // CAPTURE(p);
1042  // CAPTURE(x);
1043  // CAPTURE(val);
1044  // CAPTURE(res);
1045  // CHECK( check_abs(val,res,acc) );
1046  // }
1047  //
1048  // fluid = std::string("INCOMP::ExamplePure");
1049  // T = +55 + 273.15;
1050  // p = 10e5;
1051  //
1052  // // Compare d
1053  // val = 7.3646e+02;
1054  // res = CoolProp::PropsSI("D","T",T,"P",p,fluid);
1055  // {
1056  // CAPTURE(T);
1057  // CAPTURE(p);
1058  // CAPTURE(x);
1059  // CAPTURE(val);
1060  // CAPTURE(res);
1061  // CHECK( check_abs(val,res,acc) );
1062  // }
1063  //
1064  // // Compare cp
1065  // val = 2.2580e+03;
1066  // res = CoolProp::PropsSI("C","T",T,"P",p,fluid);
1067  // {
1068  // CAPTURE(T);
1069  // CAPTURE(p);
1070  // CAPTURE(x);
1071  // CAPTURE(val);
1072  // CAPTURE(res);
1073  // CHECK( check_abs(val,res,acc) );
1074  // }
1075  // }
1076 }
1077 
1078 #endif /* ENABLE_CATCH */