CoolProp 6.8.1dev
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
17#include "IncompressibleFluid.h"
19#include "DataStructures.h"
20#include "Solvers.h"
21#include "MatrixMath.h"
22
23namespace 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
45IncompressibleBackend::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
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) << 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;
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 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
193void 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
212void 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
238void 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
264void 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
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
522 return calc_dhdTatPxdT(T, p, x) + p * calc_dhdpatTx(T, fluid->rho(T, p, x), calc_drhodTatPx(T, p, x));
523};
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]
559double 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]
564double 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
582TEST_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 */