2# ifndef _CRTDBG_MAP_ALLOC
3# define _CRTDBG_MAP_ALLOC
5# ifndef _CRT_SECURE_NO_WARNINGS
6# define _CRT_SECURE_NO_WARNINGS
14#if defined(__ISWINDOWS__)
25# define DBL_EPSILON std::numeric_limits<double>::epsilon()
56#if defined(ENABLE_CATCH)
57# include <catch2/catch_all.hpp>
64static std::atomic<int> debug_level{0};
83static std::string error_string;
84static std::string warning_string;
85static std::mutex message_mutex;
99 std::scoped_lock lock(message_mutex);
100 warning_string = warning;
103 std::scoped_lock lock(message_mutex);
104 error_string = error;
109 i = fluid_string.find(
"::");
110 return i != std::string::npos;
113void extract_backend(std::string fluid_string, std::string& backend, std::string& fluid) {
117 if (fluid_string.find(
"REFPROP-MIX:") == 0) {
118 fluid_string.replace(0, 12,
"REFPROP::");
120 if (fluid_string.find(
"REFPROP-") == 0) {
121 fluid_string.replace(0, 8,
"REFPROP::");
125 backend = fluid_string.substr(0, i);
127 fluid = fluid_string.substr(i + 2);
130 fluid = fluid_string;
133 std::cout <<
format(
"%s:%d: backend extracted. backend: %s. fluid: %s\n", __FILE__, __LINE__, backend.c_str(), fluid.c_str());
138 return (fluid_string.find(
'[') != std::string::npos && fluid_string.find(
']') != std::string::npos);
142 return (fluid_string.find(
'-') != std::string::npos && fluid_string.find(
'%') != std::string::npos);
158 std::vector<std::string> names;
161 std::vector<std::string> pairs =
strsplit(fluid_string,
'&');
163 for (std::size_t i = 0; i < pairs.size(); ++i) {
164 const std::string& fluid = pairs[i];
167 if (fluid[fluid.size() - 1] !=
']')
throw ValueError(
format(
"Fluid entry [%s] must end with ']' character", pairs[i].c_str()));
170 std::vector<std::string> name_fraction =
strsplit(fluid.substr(0, fluid.size() - 1),
'[');
172 if (name_fraction.size() != 2) {
173 throw ValueError(
format(
"Could not break [%s] into name/fraction", fluid.substr(0, fluid.size() - 1).c_str()));
177 const std::string &name = name_fraction[0], &fraction = name_fraction[1];
183 std::stringstream ssfraction(fraction);
185 ssfraction.imbue(std::locale(ssfraction.getloc(),
new delim(c)));
188 if (ssfraction.rdbuf()->in_avail() != 0) {
189 throw ValueError(
format(
"fraction [%s] was not converted fully", fraction.c_str()));
192 if (f > 1 || f < 0) {
193 throw ValueError(
format(
"fraction [%s] was not converted to a value between 0 and 1 inclusive", fraction.c_str()));
200 fractions.push_back(f);
203 names.push_back(name);
208 std::cout <<
format(
"%s:%d: Detected fractions of %s for %s.", __FILE__, __LINE__,
vec_to_string(fractions).c_str(),
209 (
strjoin(names,
"&")).c_str());
216 std::vector<std::string> fluid_parts =
strsplit(fluid_string,
'-');
218 if (fluid_parts.size() != 2) {
220 format(R
"(Format of incompressible solution string [%s] is invalid, should be like "EG-20%" or "EG-0.2" )", fluid_string.c_str()));
224 char* pEnd =
nullptr;
225 x = strtod(fluid_parts[1].c_str(), &pEnd);
231 fractions.push_back(x);
233 std::cout <<
format(
"%s:%d: Detected incompressible concentration of %s for %s.", __FILE__, __LINE__,
vec_to_string(fractions).c_str(),
234 fluid_parts[0].c_str());
235 return fluid_parts[0];
241void _PropsSI_initialize(
const std::string& backend,
const std::vector<std::string>& fluid_names,
const std::vector<double>& z,
242 shared_ptr<AbstractState>& State) {
244 if (fluid_names.empty()) {
245 throw ValueError(
"fluid_names cannot be empty");
248 std::vector<double> fractions(1, 1.0);
249 const std::vector<double>* fractions_ptr =
nullptr;
251 if (fluid_names.size() > 1) {
256 }
else if (fluid_names.size() == 1) {
261 fractions_ptr = &fractions;
267 fractions_ptr = &fractions;
278 if (!State->available_in_high_level()) {
280 "This AbstractState derived class cannot be used in the high-level interface; see www.coolprop.org/dev/coolprop/LowLevelAPI.html");
284 if (State->using_mole_fractions()) {
286 if (State->get_mole_fractions().empty()) {
287 State->set_mole_fractions(*fractions_ptr);
289 }
else if (State->using_mass_fractions()) {
290 State->set_mass_fractions(*fractions_ptr);
291 }
else if (State->using_volu_fractions()) {
292 State->set_volu_fractions(*fractions_ptr);
295 std::cout <<
format(
"%s:%d: _PropsSI, could not set composition to %s, defaulting to mole fraction.\n", __FILE__, __LINE__,
317 std::vector<output_parameter> outputs;
318 for (
const auto& Output : Outputs) {
337 outputs.push_back(out);
344 const std::vector<double>& in1,
const std::vector<double>& in2, std::vector<std::vector<double>>& IO) {
347 if (in1.size() != in2.size()) {
348 throw ValueError(
format(
"lengths of in1 [%d] and in2 [%d] are not the same", in1.size(), in2.size()));
359 const bool one_input_one_output = (in1.size() == 1 && in2.size() == 1 && output_parameters.size() == 1);
361 bool all_trivial_outputs =
true;
362 for (
const auto& j : output_parameters) {
364 all_trivial_outputs =
false;
369 bool all_outputs_in_inputs =
true;
374 for (
const auto& j : output_parameters) {
376 all_outputs_in_inputs =
false;
379 if (!(j.Of1 == p1 || j.Of1 == p2)) {
380 all_outputs_in_inputs =
false;
385 if (!all_trivial_outputs) {
386 throw ValueError(
format(
"Input pair variable is invalid and output(s) are non-trivial; cannot do state update"));
388 all_outputs_in_inputs =
false;
392 std::cout <<
format(
"%s (%d): input pair = %d ", __FILE__, __LINE__, input_pair) <<
'\n';
393 std::cout <<
format(
"%s (%d): in1 = %s ", __FILE__, __LINE__,
vec_to_string(in1).c_str()) <<
'\n';
394 std::cout <<
format(
"%s (%d): in2 = %s ", __FILE__, __LINE__,
vec_to_string(in2).c_str()) <<
'\n';
402 const std::size_t N1 = std::max(
static_cast<std::size_t
>(1), in1.size());
403 const std::size_t N2 = std::max(
static_cast<std::size_t
>(1), output_parameters.size());
404 IO.resize(N1, std::vector<double>(N2, _HUGE));
407 bool success =
false;
408 bool success_inner =
false;
411 std::cout <<
format(
"%s (%d): Iterating over %d input value pairs.", __FILE__, __LINE__, IO.size()) <<
'\n';
415 for (std::size_t i = 0; i < IO.size(); ++i) {
417 success_inner =
false;
419 if (input_pair !=
INPUT_PAIR_INVALID && !all_trivial_outputs && !all_outputs_in_inputs) {
421 if (!use_guesses || i == 0) {
422 State->update(input_pair, in1[i], in2[i]);
424 State->update_with_guesses(input_pair, in1[i], in2[i], guesses);
429 if (one_input_one_output) {
434 for (
double& j : IO[i]) {
440 for (std::size_t j = 0; j < IO[i].size(); ++j) {
442 if (all_outputs_in_inputs) {
443 if (p1 == output_parameters[j].Of1) {
445 success_inner =
true;
447 }
else if (p2 == output_parameters[j].Of1) {
449 success_inner =
true;
457 switch (output.
type) {
460 IO[i][j] = State->keyed_output(output.
Of1);
462 switch (output.
Of1) {
467 guesses.
T = IO[i][j];
470 guesses.
p = IO[i][j];
473 guesses.
hmolar = IO[i][j];
476 guesses.
smolar = IO[i][j];
479 throw ValueError(
"Don't understand this parameter");
484 IO[i][j] = State->first_partial_deriv(output.
Of1, output.
Wrt1, output.
Constant1);
487 IO[i][j] = State->first_saturation_deriv(output.
Of1, output.
Wrt1);
497 success_inner =
true;
499 if (one_input_one_output) {
507 if (use_guesses && success_inner) {
510 guesses.
rhomolar = State->rhomolar();
517 guesses.
T = State->T();
524 success |= success_inner;
526 if (success ==
false) {
532bool StripPhase(std::string& Name, shared_ptr<AbstractState>& State)
535 std::vector<std::string> strVec =
strsplit(Name,
'|');
536 if (strVec.size() > 1) {
538 const std::string strBackend = State->backend_name();
540 throw ValueError(
"Cannot set phase on Incompressible Fluid; always liquid phase");
542 throw ValueError(
"Can't set phase on IF97 Backend");
544 throw ValueError(
"Can't set phase on TTSE Backend in PropsSI");
546 throw ValueError(
"Can't set phase on BICUBIC Backend in PropsSI");
548 throw ValueError(
"Can't set phase on VTPR Backend in PropsSI");
551 if (strVec.size() > 2)
556 std::basic_string<char>::iterator str_Iter;
557 std::string strPhase = strVec[1];
558 if (strPhase.find(
"iphase_") != strPhase.npos) {
559 str_Iter = strPhase.erase(strPhase.begin());
561 if (strPhase.find(
"phase_") == strPhase.npos) {
562 strPhase.insert(0,
"phase_");
566 throw ValueError(
format(
"Phase string \"%s\" is not a valid phase", strVec[1]));
570 State->specify_phase(imposed);
576void _PropsSImulti(
const std::vector<std::string>& Outputs,
const std::string& Name1,
const std::vector<double>& Prop1,
const std::string& Name2,
577 const std::vector<double>& Prop2,
const std::string& backend,
const std::vector<std::string>& fluids,
578 const std::vector<double>& fractions, std::vector<std::vector<double>>& IO) {
579 shared_ptr<AbstractState> State;
582 std::vector<output_parameter> output_parameters;
583 std::vector<double> v1, v2;
588 }
catch (std::exception& e) {
590 throw ValueError(
format(R
"(Initialize failed for backend: "%s", fluid: "%s" fractions "%s"; error: %s)", backend.c_str(),
595 std::string N1 = Name1;
596 std::string N2 = Name2;
599 if (HasPhase1 && HasPhase2)
600 throw ValueError(
"Phase can only be specified on one of the input key strings");
605 }
catch (std::exception& e) {
607 throw ValueError(
format(R
"(Input pair parsing failed for Name1: "%s", Name2: "%s"; err: %s)", Name1.c_str(), Name2.c_str(), e.what()));
612 }
catch (std::exception& e) {
614 throw ValueError(
format(
"Output parameter parsing failed; error: %s", e.what()));
622std::vector<std::vector<double>>
PropsSImulti(
const std::vector<std::string>& Outputs,
const std::string& Name1,
const std::vector<double>& Prop1,
623 const std::string& Name2,
const std::vector<double>& Prop2,
const std::string& backend,
624 const std::vector<std::string>& fluids,
const std::vector<double>& fractions) {
625 std::vector<std::vector<double>> IO;
627#if !defined(NO_ERROR_CATCHING)
632 _PropsSImulti(Outputs, Name1, Prop1, Name2, Prop2, backend, fluids, fractions, IO);
637#if !defined(NO_ERROR_CATCHING)
638 }
catch (
const std::exception& e) {
640# if defined(PROPSSI_ERROR_STDOUT)
641 std::cout << e.what() << std::endl;
644 std::cout << e.what() <<
'\n';
654double PropsSI(
const std::string& Output,
const std::string& Name1,
double Prop1,
const std::string& Name2,
double Prop2,
655 const std::string& FluidName) {
656#if !defined(NO_ERROR_CATCHING)
663 std::string backend, fluid;
665 std::vector<double> fractions(1, 1.0);
668 std::vector<std::vector<double>> IO;
669 _PropsSImulti(
strsplit(Output,
'&'), Name1, std::vector<double>(1, Prop1), Name2, std::vector<double>(1, Prop2), backend,
670 strsplit(fluid_string,
'&'), fractions, IO);
674 if (IO.size() != 1 || IO[0].size() != 1) {
678 const double val = IO[0][0];
681 std::cout <<
format(
"_PropsSI will return %g", val) <<
'\n';
685#if !defined(NO_ERROR_CATCHING)
686 }
catch (
const std::exception& e) {
688 +
format(R
"( : PropsSI("%s","%s",%0.10g,"%s",%0.10g,"%s"))", Output.c_str(), Name1.c_str(), Prop1, Name2.c_str(), Prop2,
690# if defined(PROPSSI_ERROR_STDOUT)
691 std::cout << e.what() << std::endl;
694 std::cout << e.what() <<
'\n';
704 if (backend ==
"SRK" || backend ==
"PR") {
707 }
else if (backend ==
"HEOS") {
710 }
else if (backend ==
"PCSAFT") {
714 throw ValueError(
format(
"You have provided an invalid backend [%s] to add_fluids_as_JSON; valid options are SRK, PR, HEOS", backend.c_str()));
721#if defined(ENABLE_CATCH)
727#if defined(ENABLE_CATCH)
729TEST_CASE(
"Check inputs to PropsSI",
"[PropsSI]") {
730 SECTION(
"Single state, single output") {
733 SECTION(
"Single state, single output, saturation derivative") {
736 SECTION(
"Single state, single output, pure incompressible") {
739 SECTION(
"Single state, trivial output, pure incompressible") {
742 SECTION(
"Bad input pair") {
745 SECTION(
"Single state, single output, 40% incompressible") {
748 SECTION(
"Single state, single output, predefined CoolProp mixture") {
751 SECTION(
"Single state, single output") {
754 SECTION(
"Single state, single output, predefined mixture") {
757 SECTION(
"Single state, single output, predefined mixture from REFPROP") {
761 SECTION(
"Single state, single output, bad predefined mixture from REFPROP") {
765 SECTION(
"Predefined mixture") {
766 std::vector<double> p(1, 101325), Q(1, 1.0), z;
767 std::vector<std::string> outputs(1,
"T");
768 outputs.emplace_back(
"Dmolar");
769 std::vector<std::vector<double>> IO;
770 std::vector<std::string> fluids(1,
"R410A.mix");
773 SECTION(
"Single state, two outputs") {
774 std::vector<double> p(1, 101325), Q(1, 1.0), z(1, 1.0);
775 std::vector<std::string> outputs(1,
"T");
776 outputs.emplace_back(
"Dmolar");
777 std::vector<std::string> fluids(1,
"Water");
780 SECTION(
"Single state, two bad outputs") {
781 std::vector<double> p(1, 101325), Q(1, 1.0), z(1, 1.0);
782 std::vector<std::vector<double>> IO;
783 std::vector<std::string> outputs(1,
"???????");
784 outputs.emplace_back(
"?????????");
785 std::vector<std::string> fluids(1,
"Water");
787 CHECK(IO.size() == 0);
789 SECTION(
"Two states, one output") {
790 std::vector<double> p(2, 101325), Q(2, 1.0), z(1, 1.0);
791 std::vector<std::string> outputs(1,
"T");
792 std::vector<std::string> fluids(1,
"Water");
795 SECTION(
"Two states, two outputs") {
796 std::vector<double> p(2, 101325), Q(2, 1.0), z(1, 1.0);
797 std::vector<std::string> outputs(1,
"T");
798 outputs.emplace_back(
"Dmolar");
799 std::vector<std::string> fluids(1,
"Water");
802 SECTION(
"cp and its derivative representation") {
803 std::vector<double> p(1, 101325), Q(1, 1.0), z(1, 1.0);
804 std::vector<std::vector<double>> IO;
805 std::vector<std::string> outputs(1,
"Cpmolar");
806 outputs.emplace_back(
"d(Hmolar)/d(T)|P");
807 std::vector<std::string> fluids(1,
"Water");
811 REQUIRE(!IO.empty());
814 CHECK(std::abs(IO[0][0] - IO[0][1]) < 1e-5);
816 SECTION(
"bad fluid") {
817 std::vector<double> p(1, 101325), Q(1, 1.0), z(1, 1.0);
818 std::vector<std::vector<double>> IO;
819 std::vector<std::string> outputs(1,
"Cpmolar");
820 outputs.emplace_back(
"d(Hmolar)/d(T)|P");
821 std::vector<std::string> fluids(1,
"????????");
827 SECTION(
"bad mole fraction length") {
828 std::vector<double> p(1, 101325), Q(1, 1.0), z(1, 1.0);
829 std::vector<std::vector<double>> IO;
830 std::vector<std::string> outputs(1,
"T");
831 std::vector<std::string> fluids(1,
"Water&Ethanol");
837 SECTION(
"bad input lengths") {
838 std::vector<double> p(1, 101325), Q(2, 1.0), z(100, 1.0);
839 std::vector<std::vector<double>> IO;
840 std::vector<std::string> outputs(1,
"Cpmolar");
841 outputs.emplace_back(
"d(Hmolar)/d(T)|P");
842 std::vector<std::string> fluids(1,
"Water");
848 SECTION(
"bad input pair") {
849 std::vector<double> Q(2, 1.0), z(1, 1.0);
850 std::vector<std::vector<double>> IO;
851 std::vector<std::string> outputs(1,
"Cpmolar");
852 outputs.emplace_back(
"d(Hmolar)/d(T)|P");
853 std::vector<std::string> fluids(1,
"Water");
866double Props1SI(std::string FluidName, std::string Output) {
869 if (valid_fluid1 && valid_fluid2) {
870 set_error_string(
format(
"Both inputs to Props1SI [%s,%s] are valid fluids", Output.c_str(), FluidName.c_str()));
873 if (!valid_fluid1 && !valid_fluid2) {
874 set_error_string(
format(
"Neither input to Props1SI [%s,%s] is a valid fluid", Output.c_str(), FluidName.c_str()));
877 if (!valid_fluid1 && valid_fluid2) {
879 std::swap(Output, FluidName);
883 const double val1 =
PropsSI(Output,
"", 0,
"", 0, FluidName);
885 set_error_string(
format(
"Unable to use input parameter [%s] in Props1SI for fluid %s; error was %s", Output.c_str(), FluidName.c_str(),
893std::vector<std::vector<double>>
Props1SImulti(
const std::vector<std::string>& Outputs,
const std::string& backend,
894 const std::vector<std::string>& fluids,
const std::vector<double>& fractions) {
895 std::vector<double> zero_vector(1, 0.);
896 std::vector<std::vector<double>> val1 =
PropsSImulti(Outputs,
"", zero_vector,
"", zero_vector, backend, fluids, fractions);
901#if defined(ENABLE_CATCH)
902TEST_CASE(
"Check inputs to Props1SI",
"[Props1SI],[PropsSI]") {
903 SECTION(
"Good fluid, good parameter") {
906 SECTION(
"Good fluid, good parameter") {
909 SECTION(
"Good fluid, good parameter, inverted") {
912 SECTION(
"Good fluid, bad parameter") {
915 SECTION(
"Bad fluid, good parameter") {
923 std::string backend, fluid;
924 std::vector<double> fractions;
935double saturation_ancillary(
const std::string& fluid_name,
const std::string& output,
int Q,
const std::string& input,
double value) {
938 std::vector<std::string> names(1, fluid_name);
947 std::string backend, fluid;
949 if (backend ==
"REFPROP") {
951 int ierr = 0, ixflag = 1;
952 double h0 = 0, s0 = 0, t0 = 0, p0 = 0;
953 std::array<char, 255> herr{};
954 std::array<char, 4> hrf{};
956 const char* refstate = reference_state.c_str();
957 if (strlen(refstate) > 3) {
958 if (reference_state ==
"ASHRAE") {
959 strncpy(hrf.data(),
"ASH", hrf.size() - 1);
960 hrf[hrf.size() - 1] =
'\0';
962 throw ValueError(
format(
"Reference state string [%s] is more than 3 characters long", reference_state.c_str()));
965 strncpy(hrf.data(), refstate, hrf.size() - 1);
966 hrf[hrf.size() - 1] =
'\0';
968 REFPROP_SETREF(hrf.data(), ixflag, x0, h0, s0, t0, p0, ierr, herr.data(), 3, 255);
969 }
else if (backend ==
"HEOS" || backend ==
"?") {
971 if (reference_state ==
"IIR") {
973 throw ValueError(
format(
"Cannot use IIR reference state; Ttriple [%Lg] is greater than 273.15 K", HEOS.
Ttriple()));
978 double deltah = HEOS.
hmass() - 200000;
979 double deltas = HEOS.
smass() - 1000;
985 std::cout <<
format(
"set offsets to %0.15g and %0.15g\n", delta_a1, delta_a2);
987 }
else if (reference_state ==
"ASHRAE") {
989 throw ValueError(
format(
"Cannot use ASHRAE reference state; Ttriple [%Lg] is greater than than 233.15 K", HEOS.
Ttriple()));
994 double deltah = HEOS.
hmass() - 0;
995 double deltas = HEOS.
smass() - 0;
1001 std::cout <<
format(
"set offsets to %0.15g and %0.15g\n", delta_a1, delta_a2);
1003 }
else if (reference_state ==
"NBP") {
1005 throw ValueError(
format(
"Cannot use NBP reference state; p_triple [%Lg Pa] is greater than than 101325 Pa", HEOS.
p_triple()));
1010 double deltah = HEOS.
hmass() - 0;
1011 double deltas = HEOS.
smass() - 0;
1017 std::cout <<
format(
"set offsets to %0.15g and %0.15g\n", delta_a1, delta_a2);
1019 }
else if (reference_state ==
"DEF") {
1021 }
else if (reference_state ==
"RESET") {
1024 throw ValueError(
format(
"Reference state string is invalid: [%s]", reference_state.c_str()));
1029 std::vector<std::string> _comps(1, FluidName);
1035 double deltah = HEOS.
hmolar() - hmolar0;
1036 double deltas = HEOS.
smolar() - smolar0;
1043 if (ParamName ==
"version") {
1045 }
else if (ParamName ==
"gitrevision") {
1047 }
else if (ParamName ==
"errstring") {
1048 std::scoped_lock lock(message_mutex);
1049 std::string temp = error_string;
1052 }
else if (ParamName ==
"warnstring") {
1053 std::scoped_lock lock(message_mutex);
1054 std::string temp = warning_string;
1055 warning_string =
"";
1057 }
else if (ParamName ==
"FluidsList" || ParamName ==
"fluids_list" || ParamName ==
"fluidslist") {
1059 }
else if (ParamName ==
"incompressible_list_pure") {
1061 }
else if (ParamName ==
"incompressible_list_solution") {
1063 }
else if (ParamName ==
"mixture_binary_pairs_list") {
1065 }
else if (ParamName ==
"parameter_list") {
1067 }
else if (ParamName ==
"predefined_mixtures") {
1069 }
else if (ParamName ==
"HOME") {
1071 }
else if (ParamName ==
"REFPROP_version") {
1073 }
else if (ParamName ==
"cubic_fluids_schema") {
1075 }
else if (ParamName ==
"cubic_fluids_list") {
1077 }
else if (ParamName ==
"pcsaft_fluids_schema") {
1080 throw ValueError(
format(
"Input parameter [%s] is invalid", ParamName.c_str()));
1083#if defined(ENABLE_CATCH)
1084TEST_CASE(
"Check inputs to get_global_param_string",
"[get_global_param_string]") {
1085 const int num_good_inputs = 8;
1086 std::string good_inputs[num_good_inputs] = {
1087 "version",
"gitrevision",
"fluids_list",
"incompressible_list_pure",
"incompressible_list_solution",
"mixture_binary_pairs_list",
1088 "parameter_list",
"predefined_mixtures"};
1089 std::ostringstream ss3c;
1090 for (
const auto& good_input : good_inputs) {
1091 ss3c <<
"Test for" << good_input;
1092 SECTION(ss3c.str(),
"") {
1105TEST_CASE(
"errstring/warnstring survive cross-thread retrieval",
"[get_global_param_string],[3211]") {
1110 const std::string emsg =
"cross-thread error payload #3211";
1111 const std::string wmsg =
"cross-thread warning payload #3211";
1120 std::string got_err, got_warn;
1126 CHECK(got_err == emsg);
1127 CHECK(got_warn == wmsg);
1135 std::string backend, fluid;
1138 return AS->fluid_param_string(ParamName);
1140#if defined(ENABLE_CATCH)
1141TEST_CASE(
"Check inputs to get_fluid_param_string",
"[get_fluid_param_string]") {
1142 const int num_good_inputs = 10;
1143 std::string good_inputs[num_good_inputs] = {
"aliases",
1147 "BibTeX-CONDUCTIVITY",
1150 "BibTeX-SURFACE_TENSION",
1151 "BibTeX-MELTING_LINE",
1152 "BibTeX-VISCOSITY"};
1153 std::ostringstream ss3c;
1154 for (
const auto& good_input : good_inputs) {
1155 ss3c <<
"Test for" << good_input;
1156 SECTION(ss3c.str(),
"") {
1173 return "supercritical";
1175 return "supercritical_gas";
1177 return "supercritical_liquid";
1179 return "critical_point";
1187 return "not_imposed";
1189 throw ValueError(
"I should never be thrown");
1191std::string
PhaseSI(
const std::string& Name1,
double Prop1,
const std::string& Name2,
double Prop2,
const std::string& FluidName) {
1192 double Phase_double =
PropsSI(
"Phase", Name1, Prop1, Name2, Prop2, FluidName);
1196 if (strError !=
"") {
1197 strPhase.append(
": " + strError);
1201 auto Phase_int =
static_cast<std::size_t
>(Phase_double);