CoolProp 8.0.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/CoolProp.h"
15
22
23namespace CoolProp {
24
26 throw NotImplementedError("Empty constructor is not implemented for incompressible fluids");
27 //this->fluid = NULL;
28}
29
31
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
45IncompressibleBackend::IncompressibleBackend(const std::string& fluid_name) : fluid(&get_incompressible_fluid(fluid_name)) {
46
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
55IncompressibleBackend::IncompressibleBackend(const std::vector<std::string>& component_names) {
56 throw NotImplementedError("Mixture-style constructor is not implemented yet for incompressible fluids");
57}
58
59void 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) << '\n';
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()) << '\n';
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) << '\n';
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) << '\n';
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) << '\n';
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 << '\n';
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
176void IncompressibleBackend::set_reference_state(double T0, double p0, double x0, double h0, double s0) {
177 // Explicit scope: this method is reachable from the ctor
178 // (IncompressibleBackend(IncompressibleFluid*) calls
179 // set_reference_state()), so the virtual clear() would bypass
180 // derived overrides anyway. Make that explicit.
183 this->_hmass_ref.clear();
184 this->_smass_ref.clear();
185 //
186 this->_T_ref = T0;
187 this->_p_ref = p0;
188 this->_x_ref = x0;
189 this->_h_ref = h0;
190 this->_s_ref = s0;
191}
192
194
197void IncompressibleBackend::set_fractions(const std::vector<CoolPropDbl>& fractions) {
198 if (get_debug_level() >= 10)
199 std::cout << format("Incompressible backend: Called set_fractions with %s ", vec_to_string(fractions).c_str()) << '\n';
200 if (fractions.size() != 1)
201 throw ValueError(format("The incompressible backend only supports one entry in the fraction vector and not %d.", fractions.size()));
202 if ((this->_fractions.size() != 1) || (this->_fractions[0] != fractions[0])) { // Change it!
203 if (get_debug_level() >= 20)
204 std::cout << format("Incompressible backend: Updating the fractions triggered a change in reference state %s -> %s",
205 vec_to_string(this->_fractions).c_str(), vec_to_string(fractions).c_str())
206 << '\n';
207 this->_fractions = fractions;
208 set_reference_state(T_ref(), p_ref(), this->_fractions[0], h_ref(), s_ref());
209 }
210}
211
213
216void IncompressibleBackend::set_mole_fractions(const std::vector<CoolPropDbl>& mole_fractions) {
217 if (get_debug_level() >= 10)
218 std::cout << format("Incompressible backend: Called set_mole_fractions with %s ", vec_to_string(mole_fractions).c_str()) << '\n';
219 if (mole_fractions.size() != 1)
220 throw ValueError(format("The incompressible backend only supports one entry in the mole fraction vector and not %d.", mole_fractions.size()));
221 if ((fluid->getxid() == IFRAC_PURE) && true) { //( this->_fractions[0]!=1.0 )){
222 this->set_fractions(std::vector<CoolPropDbl>(1, 1.0));
223 if (get_debug_level() >= 20)
224 std::cout << format("Incompressible backend: Overwriting fractions for pure fluid with %s -> %s", vec_to_string(mole_fractions).c_str(),
225 vec_to_string(this->_fractions).c_str())
226 << '\n';
227 } else if (fluid->getxid() == IFRAC_MOLE) {
228 this->set_fractions(mole_fractions);
229 } else {
230 std::vector<CoolPropDbl> tmp_fractions;
231 tmp_fractions.reserve(mole_fractions.size());
232 for (auto mole_fraction : mole_fractions) {
233 tmp_fractions.push_back((CoolPropDbl)fluid->inputFromMole(0.0, mole_fraction));
234 }
235 this->set_fractions(tmp_fractions);
236 }
237}
238
240
243void IncompressibleBackend::set_mass_fractions(const std::vector<CoolPropDbl>& mass_fractions) {
244 if (get_debug_level() >= 10)
245 std::cout << format("Incompressible backend: Called set_mass_fractions with %s ", vec_to_string(mass_fractions).c_str()) << '\n';
246 if (mass_fractions.size() != 1)
247 throw ValueError(format("The incompressible backend only supports one entry in the mass fraction vector and not %d.", mass_fractions.size()));
248 if ((fluid->getxid() == IFRAC_PURE) && true) { // ( this->_fractions[0]!=1.0 )) {
249 this->set_fractions(std::vector<CoolPropDbl>(1, 1.0));
250 if (get_debug_level() >= 20)
251 std::cout << format("Incompressible backend: Overwriting fractions for pure fluid with %s -> %s", vec_to_string(mass_fractions).c_str(),
252 vec_to_string(this->_fractions).c_str())
253 << '\n';
254 } else if (fluid->getxid() == IFRAC_MASS) {
255 this->set_fractions(mass_fractions);
256 } else {
257 std::vector<CoolPropDbl> tmp_fractions;
258 tmp_fractions.reserve(mass_fractions.size());
259 for (auto mass_fraction : mass_fractions) {
260 tmp_fractions.push_back((CoolPropDbl)fluid->inputFromMass(0.0, mass_fraction));
261 }
262 this->set_fractions(tmp_fractions);
263 }
264}
265
267
270void IncompressibleBackend::set_volu_fractions(const std::vector<CoolPropDbl>& volu_fractions) {
271 if (get_debug_level() >= 10)
272 std::cout << format("Incompressible backend: Called set_volu_fractions with %s ", vec_to_string(volu_fractions).c_str()) << '\n';
273 if (volu_fractions.size() != 1)
274 throw ValueError(
275 format("The incompressible backend only supports one entry in the volume fraction vector and not %d.", volu_fractions.size()));
276 if ((fluid->getxid() == IFRAC_PURE) && true) { // ( this->_fractions[0]!=1.0 )) {
277 this->set_fractions(std::vector<CoolPropDbl>(1, 1.0));
278 if (get_debug_level() >= 20)
279 std::cout << format("Incompressible backend: Overwriting fractions for pure fluid with %s -> %s", vec_to_string(volu_fractions).c_str(),
280 vec_to_string(this->_fractions).c_str())
281 << '\n';
282 } else if (fluid->getxid() == IFRAC_VOLUME) {
283 this->set_fractions(volu_fractions);
284 } else {
285 std::vector<CoolPropDbl> tmp_fractions;
286 tmp_fractions.reserve(volu_fractions.size());
287 for (auto volu_fraction : volu_fractions) {
288 tmp_fractions.push_back((CoolPropDbl)fluid->inputFromVolume(0.0, volu_fraction));
289 }
290 this->set_fractions(tmp_fractions);
291 }
292}
293
296 throw NotImplementedError("Cannot check status for incompressible fluid");
297}
298
307 return _rhomass;
308}
311 if (!_hmass) _hmass = calc_hmass();
312 return _hmass;
313}
316 if (!_smass) _smass = calc_smass();
317 return _smass;
318}
321 if (!_umass) _umass = calc_umass();
322 return _umass;
323}
326 if (!_cmass) _cmass = calc_cmass();
327 return _cmass;
328}
329
332 return _drhodTatPx;
333}
336 return _dsdTatPx;
337}
340 return _dhdTatPx;
341}
344 return _dsdTatPxdT;
345}
348 return _dhdTatPxdT;
349}
352 return _dsdpatTx;
353}
356 return _dhdpatTx;
357}
358
361 if (!_T_ref) throw ValueError("Reference temperature is not set");
362 return _T_ref;
363}
366 if (!_p_ref) throw ValueError("Reference pressure is not set");
367 return _p_ref;
368}
371 if (!_x_ref) throw ValueError("Reference composition is not set");
372 return _x_ref;
373}
376 if (!_h_ref) throw ValueError("Reference enthalpy is not set");
377 return _h_ref;
378}
381 if (!_s_ref) throw ValueError("Reference entropy is not set");
382 return _s_ref;
383}
384
388 return _hmass_ref;
389}
393 return _smass_ref;
394}
395
397 return fluid->T_rho(rhomass, p, _fractions[0]);
398}
400
406
407 class HmassP_residual : public FuncWrapper1D
408 {
409 protected:
410 double p, x, h_in;
411 IncompressibleBackend* backend;
412
413 public:
414 HmassP_residual(IncompressibleBackend* backend, const double& p, const double& x, const double& h_in)
415 : p(p), x(x), h_in(h_in), backend(backend) {}
416 double call(double target) override {
417 return backend->raw_calc_hmass(target, p, x) - h_in; //fluid.u(target,p,x)+ p / fluid.rho(target,p,x) - h_in;
418 }
419 //double deriv(double target);
420 };
421
422 HmassP_residual res = HmassP_residual(this, p, _fractions[0], hmass - h_ref() + hmass_ref());
423
424 double macheps = DBL_EPSILON;
425 double tol = DBL_EPSILON * 1e3;
426 int maxiter = 10;
427 double result = Brent(&res, fluid->getTmin(), fluid->getTmax(), macheps, tol, maxiter);
428 //if (this->do_debug()) std::cout << "Brent solver message: " << errstring << std::endl;
429 return result;
430}
432
438
439 class PSmass_residual : public FuncWrapper1D
440 {
441 protected:
442 double p, x, s_in;
443 IncompressibleBackend* backend;
444
445 public:
446 PSmass_residual(IncompressibleBackend* backend, const double& p, const double& x, const double& s_in)
447 : p(p), x(x), s_in(s_in), backend(backend) {}
448 double call(double target) override {
449 return backend->raw_calc_smass(target, p, x) - s_in;
450 }
451 };
452
453 PSmass_residual res = PSmass_residual(this, p, _fractions[0], smass - s_ref() + smass_ref());
454
455 double macheps = DBL_EPSILON;
456 double tol = DBL_EPSILON * 1e3;
457 int maxiter = 10;
458 double result = Brent(&res, fluid->getTmin(), fluid->getTmax(), macheps, tol, maxiter);
459 //if (this->do_debug()) std::cout << "Brent solver message: " << errstring << std::endl;
460 return result;
461}
462
465//@param umass The mass internal energy in J/kg
466//@param p The pressure in Pa
467//@returns T The temperature in K
468//*/
469//CoolPropDbl IncompressibleBackend::PUmass_flash(CoolPropDbl p, CoolPropDbl umass){
470//
471// class PUmass_residual : public FuncWrapper1D {
472// protected:
473// double p,x,u_in;
474// IncompressibleBackend* fluid;
475// protected:
476// PUmass_residual(){};
477// public:
478// PUmass_residual(IncompressibleBackend* fluid, const double &p, const double &x, const double &u_in){
479// this->p = p;
480// this->x = x;
481// this->u_in = u_in;
482// this->fluid = fluid;
483// }
484// virtual ~PUmass_residual(){};
485// double call(double target){
486// return fluid->u(target,p,x) - u_in;
487// }
488// };
489//
490// PUmass_residual res = PUmass_residual(*this, p, _fractions[0], umass);
491//
492// std::string errstring;
493// double macheps = DBL_EPSILON;
494// double tol = DBL_EPSILON*1e3;
495// int maxiter = 10;
496// double result = Brent(&res, fluid->getTmin(), fluid->getTmax(), macheps, tol, maxiter, errstring);
497// //if (this->do_debug()) std::cout << "Brent solver message: " << errstring << std::endl;
498// return result;
499//}
500
503 if (param == iT && given == iP) {
504 return fluid->Tfreeze(value, _fractions[0]);
505 } else {
506 throw ValueError("For incompressibles, the only valid inputs to calc_melting_line are T(p)");
507 }
508};
510 return hmass() - _p / rhomass();
511};
512
515 return h_ref() + raw_calc_hmass(_T, _p, _fractions[0]) - hmass_ref();
516};
518 return s_ref() + raw_calc_smass(_T, _p, _fractions[0]) - smass_ref();
519};
520
523 return calc_dhdTatPxdT(T, p, x) + p * calc_dhdpatTx(T, fluid->rho(T, p, x), calc_drhodTatPx(T, p, x));
524};
526 return calc_dsdTatPxdT(T, p, x) + p * calc_dsdpatTx(fluid->rho(T, p, x), calc_drhodTatPx(T, p, x));
527};
528
531 // TODO: Can this be accelerated?
532 if ((Of == iDmass) && (Wrt == iP)) return 0.0; // incompressible!
533 if ((Of == iDmass) && (Wrt == iHmass) && (Constant == iP)) return drhodTatPx() / dhdTatPx();
534 if ((Of == iHmass) && (Wrt == iDmass) && (Constant == iP)) return dhdTatPx() / drhodTatPx();
535 if ((Of == iDmass) && (Wrt == iSmass) && (Constant == iP)) return drhodTatPx() / dsdTatPx();
536 if ((Of == iSmass) && (Wrt == iDmass) && (Constant == iP)) return dsdTatPx() / drhodTatPx();
537 if ((Of == iDmass) && (Wrt == iT) && (Constant == iP)) return drhodTatPx();
538 if ((Of == iT) && (Wrt == iDmass) && (Constant == iP)) return 1.0 / drhodTatPx();
539 //
540 if ((Of == iHmass) && (Wrt == iP) && (Constant == iT)) return dhdpatTx();
541 if ((Of == iP) && (Wrt == iHmass) && (Constant == iT)) return 1.0 / dhdpatTx();
542 if ((Of == iHmass) && (Wrt == iSmass) && (Constant == iT)) return dhdpatTx() / dsdpatTx();
543 if ((Of == iSmass) && (Wrt == iHmass) && (Constant == iT)) return dsdpatTx() / dhdpatTx();
544 if ((Of == iHmass) && (Wrt == iT) && (Constant == iP)) return dhdTatPx();
545 if ((Of == iT) && (Wrt == iHmass) && (Constant == iP)) return 1.0 / dhdTatPx();
546 //
547 if ((Of == iSmass) && (Wrt == iP) && (Constant == iT)) return dsdpatTx();
548 if ((Of == iP) && (Wrt == iSmass) && (Constant == iT)) return 1.0 / dsdpatTx();
549 if ((Of == iSmass) && (Wrt == iT) && (Constant == iP)) return dsdTatPx();
550 if ((Of == iT) && (Wrt == iSmass) && (Constant == iP)) return 1.0 / dsdTatPx();
551 //if ( (Of==iHmass) && (Wrt==iP) && (Constant==iT) ) return dsdTatPxdT();
552 //if ( (Of==iHmass) && (Wrt==iP) && (Constant==iT) ) return dhdTatPxdT();
553 throw ValueError("Incompressible fluids only support a limited subset of partial derivatives.");
554}
555
556/* Other useful derivatives
557 */
559// \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]
560double IncompressibleBackend::calc_dsdpatTx(double rho, double drhodTatPx) {
561 return 1 / rho / rho * drhodTatPx;
562}
564// \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]
565double IncompressibleBackend::calc_dhdpatTx(double T, double rho, double drhodTatPx) {
566 return 1 / rho * (1 + T / rho * drhodTatPx);
567}
568
569} // namespace CoolProp
570
571// Testing routines with fixed parameters and known results
572/* These functions try to cover as much as possible, but
573 * they still need some serious additions.
574 */
575
576#ifdef ENABLE_CATCH
577# include <math.h>
578# include <iostream>
579# include <catch2/catch_all.hpp>
580
581# include "Tests/TestObjects.h"
582
583TEST_CASE("Internal consistency checks and example use cases for the incompressible backend", "[IncompressibleBackend]") {
586
587 SECTION("Test case for Methanol from SecCool") {
588
589 // Some basic functions
590 // has to return false
591 CHECK(backend.using_mole_fractions() == false);
592
593 //void update(long input_pair, double value1, double value2);
594
595 std::vector<CoolPropDbl> fractions;
596 fractions.push_back(0.4);
597 CHECK_THROWS(backend.set_mole_fractions(fractions));
598 CHECK_NOTHROW(backend.set_mass_fractions(fractions));
599 fractions.push_back(0.4);
600 CHECK_THROWS(backend.set_mass_fractions(fractions));
601 CHECK_THROWS(backend.check_status());
602
603 // Prepare the results and compare them to the calculated values
604 double acc = 0.0001;
605 double T = 273.15 + 10;
606 double p = 10e5;
607 double x = 0.25;
608 backend.set_mass_fractions(std::vector<CoolPropDbl>(1, x));
609 double val = 0;
610 double res = 0;
611
612 //CoolProp::set_debug_level(100);
613
614 // Compare density flash
615 val = fluid.rho(T, p, x);
616 res = backend.DmassP_flash(val, p);
617 {
618 CAPTURE(T);
619 CAPTURE(p);
620 CAPTURE(x);
621 CAPTURE(val);
622 CAPTURE(res);
623 CHECK(check_abs(T, res, acc));
624 }
625
626 // call the update function to set internal variables,
627 // concentration has been set before.
628 CHECK_THROWS(backend.update(CoolProp::DmassT_INPUTS, val, T)); // First with wrong parameters
629 CHECK_NOTHROW(backend.update(CoolProp::PT_INPUTS, p, T)); // ... and then with the correct ones.
630
631 // Compare enthalpy flash
632 val = backend.hmass();
633 res = backend.HmassP_flash(val, p);
634 {
635 CAPTURE(T);
636 CAPTURE(p);
637 CAPTURE(x);
638 CAPTURE(val);
639 CAPTURE(res);
640 CHECK(check_abs(T, res, acc));
641 }
642
643 // Compare entropy flash
644 val = backend.smass();
645 res = backend.PSmass_flash(p, val);
646 {
647 CAPTURE(T);
648 CAPTURE(p);
649 CAPTURE(x);
650 CAPTURE(val);
651 CAPTURE(res);
652 CHECK(check_abs(T, res, acc));
653 }
654
656 val = fluid.visc(T, p, x);
657 res = backend.calc_viscosity();
658 {
659 CAPTURE(T);
660 CAPTURE(p);
661 CAPTURE(x);
662 CAPTURE(val);
663 CAPTURE(res);
664 CHECK(check_abs(val, res, acc));
665 }
666
668 val = fluid.cond(T, p, x);
669 res = backend.calc_conductivity();
670 {
671 CAPTURE(T);
672 CAPTURE(p);
673 CAPTURE(x);
674 CAPTURE(val);
675 CAPTURE(res);
676 CHECK(check_abs(val, res, acc));
677 }
678
679 val = fluid.rho(T, p, x);
680 res = backend.rhomass();
681 {
682 CAPTURE(T);
683 CAPTURE(p);
684 CAPTURE(x);
685 CAPTURE(val);
686 CAPTURE(res);
687 CHECK(check_abs(val, res, acc));
688 }
689
690 // val = fluid.h(T, p, x);
691 // res = backend.hmass();
692 // {
693 // CAPTURE(T);
694 // CAPTURE(p);
695 // CAPTURE(x);
696 // CAPTURE(val);
697 // CAPTURE(res);
698 // CHECK( check_abs(val,res,acc) );
699 // }
700 //
701 // val = fluid.s(T, p, x);
702 // res = backend.smass();
703 // {
704 // CAPTURE(T);
705 // CAPTURE(p);
706 // CAPTURE(x);
707 // CAPTURE(val);
708 // CAPTURE(res);
709 // CHECK( check_abs(val,res,acc) );
710 // }
711 // Make sure the result does not change -> reference state...
712 val = backend.smass();
713 backend.update(CoolProp::PT_INPUTS, p, T);
714 res = backend.smass();
715 {
716 CAPTURE(T);
717 CAPTURE(p);
718 CAPTURE(x);
719 CAPTURE(val);
720 CAPTURE(res);
721 CHECK(check_abs(val, res, acc));
722 }
723
724 val = fluid.c(T, p, x);
725 res = backend.cpmass();
726 {
727 CAPTURE(T);
728 CAPTURE(p);
729 CAPTURE(x);
730 CAPTURE(val);
731 CAPTURE(res);
732 CHECK(check_abs(val, res, acc));
733 }
734
735 res = backend.cvmass();
736 {
737 CAPTURE(T);
738 CAPTURE(p);
739 CAPTURE(x);
740 CAPTURE(val);
741 CAPTURE(res);
742 CHECK(check_abs(val, res, acc));
743 }
744
745 // Compare Tfreeze
746 val = fluid.Tfreeze(p, x); //-20.02+273.15;// 253.1293105454671;
747 res = backend.calc_T_freeze(); // -20.02+273.15;
748 {
749 CAPTURE(T);
750 CAPTURE(p);
751 CAPTURE(x);
752 CAPTURE(val);
753 CAPTURE(res);
754 CHECK(check_abs(val, res, acc));
755 }
756
757 // Testing the reference state function
758 double Tref = 20 + 273.15 - 20;
759 double pref = 101325 * 10;
760 double xref = x;
761 backend.set_reference_state(Tref, pref, xref, 0.5, 0.5);
762 backend.set_mass_fractions(std::vector<CoolPropDbl>(1, x));
763 backend.update(CoolProp::PT_INPUTS, pref, Tref);
764 val = 0.5;
765 res = backend.hmass();
766 {
767 CAPTURE(Tref);
768 CAPTURE(pref);
769 CAPTURE(val);
770 CAPTURE(res);
771 CHECK(check_abs(val, res, acc));
772 }
773
774 val = 0.5;
775 res = backend.smass();
776 {
777 CAPTURE(Tref);
778 CAPTURE(pref);
779 CAPTURE(val);
780 CAPTURE(res);
781 CHECK(check_abs(val, res, acc));
782 }
783
784 backend.set_reference_state(Tref, pref, xref, 123, 456);
785 backend.update(CoolProp::PT_INPUTS, pref, Tref);
786 val = 123;
787 res = backend.hmass();
788 {
789 CAPTURE(Tref);
790 CAPTURE(pref);
791 CAPTURE(val);
792 CAPTURE(res);
793 CHECK(check_abs(val, res, acc));
794 }
795
796 val = 456;
797 res = backend.smass();
798 {
799 CAPTURE(Tref);
800 CAPTURE(pref);
801 CAPTURE(val);
802 CAPTURE(res);
803 CHECK(check_abs(val, res, acc));
804 }
805
806 backend.set_reference_state(Tref, pref, xref, 789, 123);
807 backend.update(CoolProp::PT_INPUTS, pref, Tref);
808 val = 789;
809 res = backend.hmass();
810 {
811 CAPTURE(Tref);
812 CAPTURE(pref);
813 CAPTURE(val);
814 CAPTURE(res);
815 CHECK(check_abs(val, res, acc));
816 }
817
818 val = 123;
819 res = backend.smass();
820 {
821 CAPTURE(Tref);
822 CAPTURE(pref);
823 CAPTURE(val);
824 CAPTURE(res);
825 CHECK(check_abs(val, res, acc));
826 }
827 }
828
829 SECTION("Tests for the full implementation using PropsSI") {
830
831 // Prepare the results and compare them to the calculated values
832 std::string fluid("ExampleMelinder");
833 double acc = 0.0001;
834 double T = -5 + 273.15;
835 double p = 10e5;
836 double x = 0.3;
837 double expected = 0;
838 double actual = 0;
839
840 // Compare different inputs
841 // ... as vector
842 expected = 9.6212e+02;
843 std::vector<std::string> fluid_Melinder(1, fluid);
844 std::vector<std::vector<double>> IO = CoolProp::PropsSImulti(std::vector<std::string>(1, "D"), "T", std::vector<double>(1, T), "P",
845 std::vector<double>(1, p), "INCOMP", fluid_Melinder, std::vector<double>(1, x));
846 REQUIRE(!IO.empty());
847 actual = IO[0][0];
848 {
849 CAPTURE(T);
850 CAPTURE(p);
851 CAPTURE(x);
852 CAPTURE(expected);
853 CAPTURE(actual);
854 CHECK(check_abs(expected, actual, acc));
855 }
856 // ... as %
857 actual = CoolProp::PropsSI("D", "T", T, "P", p, "INCOMP::" + fluid + format("-%f%%", x * 100.0));
858 {
859 CAPTURE(T);
860 CAPTURE(p);
861 CAPTURE(x);
862 CAPTURE(expected);
863 CAPTURE(actual);
864 std::string errmsg = CoolProp::get_global_param_string("errstring");
865 CAPTURE(errmsg);
866 CHECK(check_abs(expected, actual, acc));
867 }
868 // ... as mass fraction
869 actual = CoolProp::PropsSI("D", "T", T, "P", p, "INCOMP::" + fluid + format("[%f]", x));
870 {
871 CAPTURE(T);
872 CAPTURE(p);
873 CAPTURE(x);
874 CAPTURE(expected);
875 CAPTURE(actual);
876 std::string name = "INCOMP::" + fluid + format("[%f]", x);
877 CAPTURE(name);
878 std::string errmsg = CoolProp::get_global_param_string("errstring");
879 CAPTURE(errmsg);
880 CHECK(check_abs(expected, actual, acc));
881 }
882 // entropy reference state problems
883 //CoolProp::set_debug_level(51);
884 expected = CoolProp::PropsSI("S", "T", T, "P", p, "INCOMP::" + fluid + format("[%f]", x));
885 actual = CoolProp::PropsSI("S", "T", T, "P", p, "INCOMP::" + fluid + format("[%f]", x));
886 {
887 CAPTURE(T);
888 CAPTURE(p);
889 CAPTURE(x);
890 CAPTURE(expected);
891 CAPTURE(actual);
892 std::string name = "INCOMP::" + fluid + format("[%f]", x);
893 CAPTURE(name);
894 std::string errmsg = CoolProp::get_global_param_string("errstring");
895 CAPTURE(errmsg);
896 CHECK(check_abs(expected, actual, acc));
897 }
898 }
899 SECTION("SecCool example") {
900 double acc = 0.0001;
901 std::string backend = "INCOMP";
902 std::vector<std::string> fluids(1, "ExampleSecCool");
903 double T = -5 + 273.15;
904 double p = 10e5;
905 double x = 0.4;
906 std::vector<double> x_vec = std::vector<double>(1, x);
907 std::vector<double> T_vec = std::vector<double>(1, T);
908 std::vector<double> p_vec = std::vector<double>(1, p);
909
910 // Compare d
911 double dexpected = 9.4844e+02;
912 std::vector<std::vector<double>> IO =
913 CoolProp::PropsSImulti(std::vector<std::string>(1, "D"), "T", T_vec, "P", p_vec, backend, fluids, x_vec);
914 REQUIRE(!IO.empty());
915 double dactual = IO[0][0];
916 {
917 CAPTURE(T);
918 CAPTURE(p);
919 CAPTURE(x);
920 CAPTURE(dexpected);
921 CAPTURE(dactual);
922 std::string errmsg = CoolProp::get_global_param_string("errstring");
923 CAPTURE(errmsg);
924 CHECK(check_abs(dexpected, dactual, acc));
925 }
926
927 // Compare cp
928 double cpexpected = 3.6304e+03;
929 double cpactual = CoolProp::PropsSImulti(std::vector<std::string>(1, "C"), "T", T_vec, "P", p_vec, backend, fluids, x_vec)[0][0];
930 {
931 CAPTURE(T);
932 CAPTURE(p);
933 CAPTURE(x);
934 CAPTURE(cpexpected);
935 CAPTURE(cpactual);
936 std::string errmsg = CoolProp::get_global_param_string("errstring");
937 CAPTURE(errmsg);
938 CHECK(check_abs(cpexpected, cpactual, acc));
939 }
940 }
941 SECTION("INCOMP::ExamplePure") {
942 double acc = 0.0001;
943 std::string fluid = std::string("INCOMP::ExamplePure");
944 double T = +55 + 273.15;
945 double p = 10e5;
946
947 // Compare d
948 double dexpected = 7.3646e+02;
949 double dactual = CoolProp::PropsSI("D", "T", T, "P", p, fluid);
950 {
951 CAPTURE(T);
952 CAPTURE(p);
953 CAPTURE(dexpected);
954 CAPTURE(dactual);
955 std::string errmsg = CoolProp::get_global_param_string("errstring");
956 CAPTURE(errmsg);
957 CHECK(check_abs(dexpected, dactual, acc));
958 }
959
960 // Compare cp
961 double cpexpected = 2.2580e+03;
962 double cpactual = CoolProp::PropsSI("C", "T", T, "P", p, fluid);
963 {
964 CAPTURE(T);
965 CAPTURE(p);
966 CAPTURE(cpexpected);
967 CAPTURE(cpactual);
968 std::string errmsg = CoolProp::get_global_param_string("errstring");
969 CAPTURE(errmsg);
970 CHECK(check_abs(cpexpected, cpactual, acc));
971 }
972 }
973
974 // SECTION("Tests for the hardcoded fluids") {
975 //
976 // // Prepare the results and compare them to the calculated values
977 // std::string fluid("INCOMP::LiBr");
978 // double acc = 0.0001;
979 // double T = 50 + 273.15;
980 // double p = 10e5;
981 // double x = 0.3;
982 // double val = 0;
983 // double res = 0;
984 //
985 // // Compare different inputs
986 // // ... as vector
987 // val = 9.6212e+02;
988 // res = CoolProp::PropsSI("D","T",T,"P",p,fluid,std::vector<double>(1,x));
989 // {
990 // CAPTURE(T);
991 // CAPTURE(p);
992 // CAPTURE(x);
993 // CAPTURE(val);
994 // CAPTURE(res);
995 // CHECK( check_abs(val,res,acc) );
996 // }
997 // // ... as %
998 // res = CoolProp::PropsSI("D","T",T,"P",p,fluid+format("-%f%s",x*100.0,"%"));
999 // {
1000 // CAPTURE(T);
1001 // CAPTURE(p);
1002 // CAPTURE(x);
1003 // CAPTURE(val);
1004 // CAPTURE(res);
1005 // CHECK( check_abs(val,res,acc) );
1006 // }
1007 // // ... as mass fraction
1008 // res = CoolProp::PropsSI("D","T",T,"P",p,fluid+format("[%f]",x));
1009 // {
1010 // CAPTURE(T);
1011 // CAPTURE(p);
1012 // CAPTURE(x);
1013 // CAPTURE(val);
1014 // CAPTURE(res);
1015 // CHECK( check_abs(val,res,acc) );
1016 // }
1017 //
1018 //
1019 // fluid = std::string("INCOMP::ExampleSecCool");
1020 // T = -5 + 273.15;
1021 // p = 10e5;
1022 // x = 0.4;
1023 // std::vector<double> x_vec = std::vector<double>(1,x);
1024 //
1025 // // Compare d
1026 // val = 9.4844e+02;
1027 // res = CoolProp::PropsSI("D","T",T,"P",p,fluid,x_vec);
1028 // {
1029 // CAPTURE(T);
1030 // CAPTURE(p);
1031 // CAPTURE(x);
1032 // CAPTURE(val);
1033 // CAPTURE(res);
1034 // CHECK( check_abs(val,res,acc) );
1035 // }
1036 //
1037 // // Compare cp
1038 // val = 3.6304e+03;
1039 // res = CoolProp::PropsSI("C","T",T,"P",p,fluid,x_vec);
1040 // {
1041 // CAPTURE(T);
1042 // CAPTURE(p);
1043 // CAPTURE(x);
1044 // CAPTURE(val);
1045 // CAPTURE(res);
1046 // CHECK( check_abs(val,res,acc) );
1047 // }
1048 //
1049 // fluid = std::string("INCOMP::ExamplePure");
1050 // T = +55 + 273.15;
1051 // p = 10e5;
1052 //
1053 // // Compare d
1054 // val = 7.3646e+02;
1055 // res = CoolProp::PropsSI("D","T",T,"P",p,fluid);
1056 // {
1057 // CAPTURE(T);
1058 // CAPTURE(p);
1059 // CAPTURE(x);
1060 // CAPTURE(val);
1061 // CAPTURE(res);
1062 // CHECK( check_abs(val,res,acc) );
1063 // }
1064 //
1065 // // Compare cp
1066 // val = 2.2580e+03;
1067 // res = CoolProp::PropsSI("C","T",T,"P",p,fluid);
1068 // {
1069 // CAPTURE(T);
1070 // CAPTURE(p);
1071 // CAPTURE(x);
1072 // CAPTURE(val);
1073 // CAPTURE(res);
1074 // CHECK( check_abs(val,res,acc) );
1075 // }
1076 // }
1077}
1078
1079#endif /* ENABLE_CATCH */