CoolProp
TabularBackends.h
1 #ifndef TABULAR_BACKENDS_H
2 #define TABULAR_BACKENDS_H
3 
4 #include "AbstractState.h"
5 #include "CPmsgpack.h"
6 #include <msgpack/fbuffer.hpp>
7 #include "crossplatform_shared_ptr.h"
8 #include "Exceptions.h"
9 #include "CoolProp.h"
10 #include <sstream>
11 #include "Configuration.h"
12 #include "Backends/Helmholtz/PhaseEnvelopeRoutines.h"
13 
18 #define LIST_OF_MATRICES X(T) X(p) X(rhomolar) X(hmolar) X(smolar) X(umolar) X(dTdx) X(dTdy) X(dpdx) X(dpdy) X(drhomolardx) X(drhomolardy) X(dhmolardx) X(dhmolardy) X(dsmolardx) X(dsmolardy) X(dumolardx) X(dumolardy) X(d2Tdx2) X(d2Tdxdy) X(d2Tdy2) X(d2pdx2) X(d2pdxdy) X(d2pdy2) X(d2rhomolardx2) X(d2rhomolardxdy) X(d2rhomolardy2) X(d2hmolardx2) X(d2hmolardxdy) X(d2hmolardy2) X(d2smolardx2) X(d2smolardxdy) X(d2smolardy2) X(d2umolardx2) X(d2umolardxdy) X(d2umolardy2) X(visc) X(cond)
19 
24 #define LIST_OF_SATURATION_VECTORS X(TL) X(pL) X(logpL) X(hmolarL) X(smolarL) X(umolarL) X(rhomolarL) X(logrhomolarL) X(viscL) X(condL) X(logviscL) X(TV) X(pV) X(logpV) X(hmolarV) X(smolarV) X(umolarV) X(rhomolarV) X(logrhomolarV) X(viscV) X(condV) X(logviscV) X(cpmolarV) X(cpmolarL) X(cvmolarV) X(cvmolarL) X(speed_soundL) X(speed_soundV)
25 
26 namespace CoolProp{
27 
29 {
30 
31 public:
32  int revision;
33 
34  PackablePhaseEnvelopeData() : revision(0) {} ;
35 
36  void copy_from_nonpackable(const PhaseEnvelopeData &PED) {
37  /* Use X macros to auto-generate the copying */
38  #define X(name) name = PED.name;
39  PHASE_ENVELOPE_VECTORS
40  #undef X
41  /* Use X macros to auto-generate the copying */
42  #define X(name) name = PED.name;
43  PHASE_ENVELOPE_MATRICES
44  #undef X
45  };
46 
47  std::map<std::string, std::vector<double> > vectors;
48  std::map<std::string, std::vector<std::vector<double> > > matrices;
49 
50  MSGPACK_DEFINE(revision, vectors, matrices); // write the member variables that you want to pack using msgpack
51 
53  void pack(){
54  /* Use X macros to auto-generate the packing code; each will look something like: matrices.insert(std::pair<std::string, std::vector<double> >("T", T)); */
55  #define X(name) vectors.insert(std::pair<std::string, std::vector<double> >(#name, name));
56  PHASE_ENVELOPE_VECTORS
57  #undef X
58  /* Use X macros to auto-generate the packing code; each will look something like: matrices.insert(std::pair<std::string, std::vector<std::vector<CoolPropDbl> > >("T", T)); */
59  #define X(name) matrices.insert(std::pair<std::string, std::vector<std::vector<double> > >(#name, name));
60  PHASE_ENVELOPE_MATRICES
61  #undef X
62  };
63  std::map<std::string, std::vector<double> >::iterator get_vector_iterator(const std::string &name){
64  std::map<std::string, std::vector<double> >::iterator it = vectors.find(name);
65  if (it == vectors.end()){
66  throw UnableToLoadError(format("could not find vector %s",name.c_str()));
67  }
68  return it;
69  }
70  std::map<std::string, std::vector<std::vector<double> > >::iterator get_matrix_iterator(const std::string &name){
71  std::map<std::string, std::vector<std::vector<double> > >::iterator it = matrices.find(name);
72  if (it == matrices.end()){
73  throw UnableToLoadError(format("could not find matrix %s", name.c_str()));
74  }
75  return it;
76  }
78  void unpack(){
79  /* Use X macros to auto-generate the unpacking code;
80  * each will look something like: T = get_vector_iterator("T")->second
81  */
82  #define X(name) name = get_vector_iterator(#name)->second;
83  PHASE_ENVELOPE_VECTORS
84  #undef X
85  /* Use X macros to auto-generate the unpacking code;
86  * each will look something like: T = get_matrix_iterator("T")->second
87  **/
88  #define X(name) name = get_matrix_iterator(#name)->second;
89  PHASE_ENVELOPE_MATRICES
90  #undef X
91  // Find the index of the point with the highest temperature
92  iTsat_max = std::distance(T.begin(), std::max_element(T.begin(), T.end()));
93  // Find the index of the point with the highest pressure
94  ipsat_max = std::distance(p.begin(), std::max_element(p.begin(), p.end()));
95  };
96  void deserialize(msgpack::object &deserialized){
98  deserialized.convert(temp);
99  temp.unpack();
100  if (revision > temp.revision){
101  throw ValueError(format("loaded revision [%d] is older than current revision [%d]", temp.revision, revision));
102  }
103  std::swap(*this, temp); // Swap if successful
104  };
105 };
106 
108 inline void mass_to_molar(parameters &param, double &conversion_factor, double molar_mass){
109  conversion_factor = 1.0;
110  switch (param){
111  case iDmass: conversion_factor = molar_mass; param = iDmolar; break;
112  case iHmass: conversion_factor /= molar_mass; param = iHmolar; break;
113  case iSmass: conversion_factor /= molar_mass; param = iSmolar; break;
114  case iUmass: conversion_factor /= molar_mass; param = iUmolar; break;
115  case iCvmass: conversion_factor /= molar_mass; param = iCvmolar; break;
116  case iCpmass: conversion_factor /= molar_mass; param = iCpmolar; break;
117  case iDmolar:
118  case iHmolar:
119  case iSmolar:
120  case iUmolar:
121  case iCvmolar:
122  case iCpmolar:
123  case iT:
124  case iP:
125  case ispeed_sound:
128  case iviscosity:
129  case iconductivity:
130  return;
131  default:
132  throw ValueError("TabularBackends::mass_to_molar - I don't know how to convert this parameter");
133  }
134 }
135 
141  public:
142  std::size_t N;
143  shared_ptr<CoolProp::AbstractState> AS;
144 
145  PureFluidSaturationTableData(){N = 1000; revision = 1;}
146 
148  void build(shared_ptr<CoolProp::AbstractState> &AS);
149 
150  /* Use X macros to auto-generate the variables; each will look something like: std::vector<double> T; */
151  #define X(name) std::vector<double> name;
152  LIST_OF_SATURATION_VECTORS
153  #undef X
154 
155  int revision;
156  std::map<std::string, std::vector<double> > vectors;
157 
158  MSGPACK_DEFINE(revision, vectors); // write the member variables that you want to pack
159 
160  /***
161  * \brief Determine if a set of inputs are single-phase or inside the saturation table
162  * @param main The main variable that is being provided (currently T or P)
163  * @param mainval The value of the main variable that is being provided
164  * @param other The secondary variable
165  * @param val The value of the secondary variable
166  * @param iL The index associated with the nearest point for the liquid
167  * @param iV The index associated with the nearest point for the vapor
168  * @param yL The value associated with the nearest point for the liquid (based on interpolation)
169  * @param yV The value associated with the nearest point for the vapor (based on interpolation)
170 
171  \note If PQ or QT are inputs, yL and yV will correspond to the other main variable: p->T or T->p
172  */
173  bool is_inside(parameters main, double mainval, parameters other, double val, std::size_t &iL, std::size_t &iV, CoolPropDbl &yL, CoolPropDbl &yV){
174  std::vector<double> *yvecL = NULL, *yvecV = NULL;
175  switch(other){
176  case iT: yvecL = &TL; yvecV = &TV; break;
177  case iHmolar: yvecL = &hmolarL; yvecV = &hmolarV; break;
178  case iQ: yvecL = &TL; yvecV = &TV; break;
179  case iSmolar: yvecL = &smolarL; yvecV = &smolarV; break;
180  case iUmolar: yvecL = &umolarL; yvecV = &umolarV; break;
181  case iDmolar: yvecL = &rhomolarL; yvecV = &rhomolarV; break;
182  default: throw ValueError("invalid input for other in is_inside");
183  }
184 
185  // Trivial checks
186  if (main == iP){
187  // If p is outside the range (ptriple, pcrit), considered to not be inside
188  double pmax = this->pV[pV.size()-1], pmin = this->pV[0];
189  if (mainval > pmax || mainval < pmin){return false;}
190  }
191  else if (main == iT){
192  // If T is outside the range (Tmin, Tcrit), considered to not be inside
193  double Tmax = this->TV[TV.size()-1], Tmin = this->TV[0];
194  if (mainval > Tmax || mainval < Tmin){return false;}
195  }
196  else{
197  throw ValueError("invalid input for other in is_inside");
198  }
199 
200  // Now check based on a rough analysis using bounding pressure
201  std::size_t iLplus, iVplus;
202  // Find the indices (iL,iL+1) & (iV,iV+1) that bound the given pressure
203  // In general iV and iL will be the same, but if pseudo-pure, they might
204  // be different
205  if (main ==iP){
206  bisect_vector(pV, mainval, iV);
207  bisect_vector(pL, mainval, iL);
208  }
209  else if (main == iT){
210  bisect_vector(TV, mainval, iV);
211  bisect_vector(TL, mainval, iL);
212  }
213  else{
214  throw ValueError(format("For now, main input in is_inside must be T or p"));
215  }
216 
217  iVplus = std::min(iV+1, N-1);
218  iLplus = std::min(iL+1, N-1);
219  if (other == iQ){
220  // Actually do "saturation" call using cubic interpolation
221  if (iVplus < 3){ iVplus = 3;}
222  if (iLplus < 3){ iLplus = 3;}
223  if (main==iP){
224  double logp = log(mainval);
225  // Calculate temperature
226  yV = CubicInterp(logpV, TV, iVplus-3, iVplus-2, iVplus-1, iVplus, logp);
227  yL = CubicInterp(logpL, TL, iLplus-3, iLplus-2, iLplus-1, iLplus, logp);
228  }
229  else if (main == iT){
230  // Calculate pressure
231  yV = exp(CubicInterp(TV, logpV, iVplus-3, iVplus-2, iVplus-1, iVplus, mainval));
232  yL = exp(CubicInterp(TL, logpL, iLplus-3, iLplus-2, iLplus-1, iLplus, mainval));
233  }
234  return true;
235  }
236  // Find the bounding values for the other variable
237  double ymin = min4((*yvecL)[iL],(*yvecL)[iLplus],(*yvecV)[iV],(*yvecV)[iVplus]);
238  double ymax = max4((*yvecL)[iL],(*yvecL)[iLplus],(*yvecV)[iV],(*yvecV)[iVplus]);
239  if (val < ymin || val > ymax){ return false;}
240  // Actually do "saturation" call using cubic interpolation
241  if (iVplus < 3){ iVplus = 3;}
242  if (iLplus < 3){ iLplus = 3;}
243  if (main==iP){
244  double logp = log(mainval);
245  yV = CubicInterp(logpV, *yvecV, iVplus-3, iVplus-2, iVplus-1, iVplus, logp);
246  yL = CubicInterp(logpL, *yvecL, iLplus-3, iLplus-2, iLplus-1, iLplus, logp);
247  }
248  else if (main == iT){
249  yV = CubicInterp(TV, *yvecV, iVplus-3, iVplus-2, iVplus-1, iVplus, mainval);
250  yL = CubicInterp(TL, *yvecL, iLplus-3, iLplus-2, iLplus-1, iLplus, mainval);
251  }
252 
253  if (!is_in_closed_range(yV, yL, static_cast<CoolPropDbl>(val))){
254  return false;
255  }
256  else{
257  iL = iLplus-1;
258  iV = iVplus-1;
259  return true;
260  }
261  }
263  void resize(std::size_t N){
264  /* Use X macros to auto-generate the code; each will look something like: T.resize(N); std::fill(T.begin(), T.end(), _HUGE); */
265  #define X(name) name.resize(N); std::fill(name.begin(), name.end(), _HUGE);
266  LIST_OF_SATURATION_VECTORS
267  #undef X
268  };
270  void pack(){
271  /* Use X macros to auto-generate the packing code; each will look something like: matrices.insert(std::pair<std::vector<std::vector<double> > >("T", T)); */
272  #define X(name) vectors.insert(std::pair<std::string, std::vector<double> >(#name, name));
273  LIST_OF_SATURATION_VECTORS
274  #undef X
275  };
276  std::map<std::string, std::vector<double> >::iterator get_vector_iterator(const std::string &name){
277  std::map<std::string, std::vector<double> >::iterator it = vectors.find(name);
278  if (it == vectors.end()){
279  throw UnableToLoadError(format("could not find vector %s",name.c_str()));
280  }
281  return it;
282  }
284  void unpack(){
285  /* Use X macros to auto-generate the unpacking code; each will look something like: T = get_vector_iterator("T")->second */
286  #define X(name) name = get_vector_iterator(#name)->second;
287  LIST_OF_SATURATION_VECTORS
288  #undef X
289  N = TL.size();
290  };
291  void deserialize(msgpack::object &deserialized){
293  deserialized.convert(temp);
294  temp.unpack();
295  if (N != temp.N)
296  {
297  throw ValueError(format("old [%d] and new [%d] sizes don't agree", temp.N, N));
298  }
299  else if (revision > temp.revision)
300  {
301  throw ValueError(format("loaded revision [%d] is older than current revision [%d]", temp.revision, revision));
302  }
303  std::swap(*this, temp); // Swap
304  this->AS = temp.AS; // Reconnect the AbstractState pointer
305  };
306  double evaluate(parameters output, double p_or_T, double Q, std::size_t iL, std::size_t iV)
307  {
308  if (iL <= 2){ iL = 2; }
309  else if (iL+1 == N){ iL = N-2; }
310  if (iV <= 2){ iV = 2; }
311  else if (iV+1 == N){ iV = N-2; }
312  double logp = log(p_or_T);
313  switch(output){
314  case iP:
315  {
316  double _logpV = CubicInterp(this->TV, logpV, iV-2, iV-1, iV, iV+1, p_or_T);
317  double _logpL = CubicInterp(this->TL, logpL, iL-2, iL-1, iL, iL+1, p_or_T);
318  return Q*exp(_logpV) + (1-Q)*exp(_logpL);
319  }
320  case iT:
321  {
322  double TV = CubicInterp(logpV, this->TV, iV-2, iV-1, iV, iV+1, logp);
323  double TL = CubicInterp(logpL, this->TL, iL-2, iL-1, iL, iL+1, logp);
324  return Q*TV + (1-Q)*TL;
325  }
326  case iSmolar:
327  {
328  double sV = CubicInterp(logpV, smolarV, iV-2, iV-1, iV, iV+1, logp);
329  double sL = CubicInterp(logpL, smolarL, iL-2, iL-1, iL, iL+1, logp);
330  return Q*sV + (1-Q)*sL;
331  }
332  case iHmolar:
333  {
334  double hV = CubicInterp(logpV, hmolarV, iV-2, iV-1, iV, iV+1, logp);
335  double hL = CubicInterp(logpL, hmolarL, iL-2, iL-1, iL, iL+1, logp);
336  return Q*hV + (1-Q)*hL;
337  }
338  case iUmolar:
339  {
340  double uV = CubicInterp(logpV, umolarV, iV-2, iV-1, iV, iV+1, logp);
341  double uL = CubicInterp(logpL, umolarL, iL-2, iL-1, iL, iL+1, logp);
342  return Q*uV + (1-Q)*uL;
343  }
344  case iDmolar:
345  {
346  double rhoV = exp(CubicInterp(logpV, logrhomolarV, iV-2, iV-1, iV, iV+1, logp));
347  double rhoL = exp(CubicInterp(logpL, logrhomolarL, iL-2, iL-1, iL, iL+1, logp));
348  if (!ValidNumber(rhoV)){throw ValueError("rhoV is invalid");}
349  if (!ValidNumber(rhoL)){throw ValueError("rhoL is invalid");}
350  return 1/(Q/rhoV + (1-Q)/rhoL);
351  }
352  case iconductivity:
353  {
354  double kV = CubicInterp(logpV, condV, iV-2, iV-1, iV, iV+1, logp);
355  double kL = CubicInterp(logpL, condL, iL-2, iL-1, iL, iL+1, logp);
356  if (!ValidNumber(kV)){throw ValueError("kV is invalid");}
357  if (!ValidNumber(kL)){throw ValueError("kL is invalid");}
358  return Q*kV + (1-Q)*kL;
359  }
360  case iviscosity:
361  {
362  double muV = exp(CubicInterp(logpV, logviscV, iV-2, iV-1, iV, iV+1, logp));
363  double muL = exp(CubicInterp(logpL, logviscL, iL-2, iL-1, iL, iL+1, logp));
364  if (!ValidNumber(muV)){throw ValueError("muV is invalid");}
365  if (!ValidNumber(muL)){throw ValueError("muL is invalid");}
366  return 1/(Q/muV + (1-Q)/muL);
367  }
368  case iCpmolar:
369  {
370  double cpV = CubicInterp(logpV, cpmolarV, iV-2, iV-1, iV, iV+1, logp);
371  double cpL = CubicInterp(logpL, cpmolarL, iL-2, iL-1, iL, iL+1, logp);
372  if (!ValidNumber(cpV)){ throw ValueError("cpV is invalid"); }
373  if (!ValidNumber(cpL)){ throw ValueError("cpL is invalid"); }
374  return Q*cpV + (1-Q)*cpL;
375  }
376  case iCvmolar:
377  {
378  double cvV = CubicInterp(logpV, cvmolarV, iV-2, iV-1, iV, iV+1, logp);
379  double cvL = CubicInterp(logpL, cvmolarL, iL-2, iL-1, iL, iL+1, logp);
380  if (!ValidNumber(cvV)){ throw ValueError("cvV is invalid"); }
381  if (!ValidNumber(cvL)){ throw ValueError("cvL is invalid"); }
382  return Q*cvV + (1-Q)*cvL;
383  }
384  case ispeed_sound:
385  {
386  double wV = CubicInterp(logpV, speed_soundV, iV-2, iV-1, iV, iV+1, logp);
387  double wL = CubicInterp(logpL, speed_soundL, iL-2, iL-1, iL, iL+1, logp);
388  if (!ValidNumber(wV)){ throw ValueError("wV is invalid"); }
389  if (!ValidNumber(wL)){ throw ValueError("wL is invalid"); }
390  return Q*wV + (1-Q)*wL;
391  }
392  default:
393  throw ValueError("Output variable for evaluate is invalid");
394  }
395  };
404  double first_saturation_deriv(parameters Of1, parameters Wrt1, int Q, double val, std::size_t i)
405  {
406  if (i < 2 || i > TL.size() - 2){throw ValueError(format("Invalid index (%d) to calc_first_saturation_deriv in TabularBackends",i));}
407  std::vector<double> *x, *y;
408  // Connect pointers for each vector
409  switch(Wrt1){
410  case iT: x = (Q == 0) ? &TL : &TV; break;
411  case iP: x = (Q == 0) ? &pL : &pV; break;
412  default: throw ValueError(format("Key for Wrt1 is invalid in calc_first_saturation_deriv"));
413  }
414  CoolPropDbl factor = 1.0;
415  switch(Of1){
416  case iT: y = (Q == 0) ? &TL : &TV; break;
417  case iP: y = (Q == 0) ? &pL : &pV; break;
418  case iDmolar: y = (Q == 0) ? &rhomolarL : &rhomolarV; break;
419  case iHmolar: y = (Q == 0) ? &hmolarL : &hmolarV; break;
420  case iSmolar: y = (Q == 0) ? &smolarL : &smolarV; break;
421  case iUmolar: y = (Q == 0) ? &umolarL : &umolarV; break;
422  case iDmass: y = (Q == 0) ? &rhomolarL : &rhomolarV; factor = AS->molar_mass(); break;
423  case iHmass: y = (Q == 0) ? &hmolarL : &hmolarV; factor = 1/AS->molar_mass(); break;
424  case iSmass: y = (Q == 0) ? &smolarL : &smolarV; factor = 1/AS->molar_mass(); break;
425  case iUmass: y = (Q == 0) ? &umolarL : &umolarV; factor = 1/AS->molar_mass(); break;
426  default: throw ValueError(format("Key for Of1 is invalid in calc_first_saturation_deriv"));
427  }
428  return CubicInterpFirstDeriv((*x)[i-2], (*x)[i-1], (*x)[i], (*x)[i+1],
429  (*y)[i-2], (*y)[i-1], (*y)[i], (*y)[i+1],
430  val)*factor;
431  };
432  //calc_first_two_phase_deriv(parameters Of, parameters Wrt, parameters Constant);
433 };
434 
440 
441  public:
442  std::size_t Nx, Ny;
443  CoolProp::parameters xkey, ykey;
444  shared_ptr<CoolProp::AbstractState> AS;
445  std::vector<double> xvec, yvec;
446  std::vector<std::vector<std::size_t> > nearest_neighbor_i, nearest_neighbor_j;
447  bool logx, logy;
448  double xmin, ymin, xmax, ymax;
449 
450  virtual void set_limits() = 0;
451 
453  Nx = 200; Ny = 200; revision = 0;
454  xkey = INVALID_PARAMETER; ykey = INVALID_PARAMETER;
455  logx = false; logy = false;
456  xmin = _HUGE; xmax = _HUGE; ymin = _HUGE; ymax = _HUGE;
457  }
458 
459  /* Use X macros to auto-generate the variables; each will look something like: std::vector< std::vector<double> > T; */
460  #define X(name) std::vector< std::vector<double> > name;
461  LIST_OF_MATRICES
462  #undef X
463  int revision;
464  std::map<std::string, std::vector<std::vector<double> > > matrices;
466  void build(shared_ptr<CoolProp::AbstractState> &AS);
467 
468  MSGPACK_DEFINE(revision, matrices, xmin, xmax, ymin, ymax); // write the member variables that you want to pack
470  void resize(std::size_t Nx, std::size_t Ny){
471  /* Use X macros to auto-generate the code; each will look something like: T.resize(Nx, std::vector<double>(Ny, _HUGE)); */
472  #define X(name) name.resize(Nx, std::vector<double>(Ny, _HUGE));
473  LIST_OF_MATRICES
474  #undef X
475  make_axis_vectors();
476  };
478  void make_axis_vectors(void){
479  if (logx){
480  xvec = logspace(xmin, xmax, Nx);
481  }
482  else{
483  xvec = linspace(xmin, xmax, Nx);
484  }
485  if (logy){
486  yvec = logspace(ymin, ymax, Ny);
487  }
488  else{
489  yvec = linspace(ymin, ymax, Ny);
490  }
491  };
494  nearest_neighbor_i.resize(Nx, std::vector<std::size_t>(Ny, std::numeric_limits<std::size_t>::max()));
495  nearest_neighbor_j.resize(Nx, std::vector<std::size_t>(Ny, std::numeric_limits<std::size_t>::max()));
496  for (std::size_t i = 0; i < xvec.size(); ++i){
497  for (std::size_t j = 0; j < yvec.size(); ++j){
498  nearest_neighbor_i[i][j] = i;
499  nearest_neighbor_j[i][j] = j;
500  if (!ValidNumber(T[i][j])){
501  int xoffsets[] = {-1,1,0,0,-1,1,1,-1};
502  int yoffsets[] = {0,0,1,-1,-1,-1,1,1};
503  // Length of offset
504  std::size_t N = sizeof(xoffsets)/sizeof(xoffsets[0]);
505  for (std::size_t k = 0; k < N; ++k){
506  std::size_t iplus = i + xoffsets[k];
507  std::size_t jplus = j + yoffsets[k];
508  if (0 < iplus && iplus < Nx-1 && 0 < jplus && jplus < Ny-1 && ValidNumber(T[iplus][jplus])){
509  nearest_neighbor_i[i][j] = iplus;
510  nearest_neighbor_j[i][j] = jplus;
511  break;
512  }
513  }
514  }
515  }
516  }
517  };
519  void pack(){
520  /* Use X macros to auto-generate the packing code; each will look something like: matrices.insert(std::pair<std::vector<std::vector<double> > >("T", T)); */
521  #define X(name) matrices.insert(std::pair<std::string, std::vector<std::vector<double> > >(#name, name));
522  LIST_OF_MATRICES
523  #undef X
524  };
525  std::map<std::string, std::vector<std::vector<double> > >::iterator get_matrices_iterator(const std::string &name){
526  std::map<std::string, std::vector<std::vector<double> > >::iterator it = matrices.find(name);
527  if (it == matrices.end()){
528  throw UnableToLoadError(format("could not find matrix %s",name.c_str()));
529  }
530  return it;
531  }
533  void unpack(){
534  /* Use X macros to auto-generate the unpacking code; each will look something like: T = *(matrices.find("T")).second */
535  #define X(name) name = get_matrices_iterator(#name)->second;
536  LIST_OF_MATRICES
537  #undef X
538  Nx = T.size(); Ny = T[0].size();
539  make_axis_vectors();
540  make_good_neighbors();
541  };
543  bool native_inputs_are_in_range(double x, double y){
544  double e = 10*DBL_EPSILON;
545  return x >= xmin-e && x <= xmax+e && y >= ymin-e && y <= ymax+e;
546  }
550  void find_native_nearest_neighbor(double x, double y, std::size_t &i, std::size_t &j){
551  bisect_vector(xvec, x, i);
552  if (i != Nx-1){
553  if(!logx){
554  if (x > (xvec[i]+xvec[i+1])/2.0){i++;}
555  }
556  else{
557  if (x > sqrt(xvec[i]*xvec[i+1])){i++;}
558  }
559  }
560  bisect_vector(yvec, y, j);
561  if (j != Ny-1){
562  if(!logy){
563  if (y > (yvec[j]+yvec[j+1])/2.0){j++;}
564  }
565  else{
566  if (y > sqrt(yvec[j]*yvec[j+1])){j++;}
567  }
568  }
569  }
571  void find_nearest_neighbor(parameters givenkey, double givenval, parameters otherkey, double otherval, std::size_t &i, std::size_t &j){
572  if (givenkey == ykey){
573  bisect_vector(yvec, givenval, j);
574  // This one is problematic because we need to make a slice against the grain in the "matrix"
575  // which requires a slightly different algorithm
576  try{
577  bisect_segmented_vector_slice(get(otherkey), j, otherval, i);
578  }
579  catch(...){
580  // Now we go for a less intelligent solution, we simply try to find the one that is the closest
581  const std::vector<std::vector<double> > & mat = get(otherkey);
582  double closest_diff = 1e20;
583  std::size_t closest_i = 0;
584  for (std::size_t index = 0; index < mat.size(); ++index){
585  double diff = std::abs(mat[index][j] - otherval);
586  if (diff < closest_diff){
587  closest_diff = diff; closest_i = index;
588  }
589  }
590  i = closest_i;
591  }
592  }
593  else if (givenkey == xkey){
594  bisect_vector(xvec, givenval, i);
595  // This one is fine because we now end up with a vector<double> in the other variable
596  const std::vector<std::vector<double> > & v = get(otherkey);
597  bisect_vector(v[i], otherval, j);
598  }
599  }
602  void find_native_nearest_good_neighbor(double x, double y, std::size_t &i, std::size_t &j){
603  // Get the node that is closest
604  find_native_nearest_neighbor(x,y,i,j);
605  // Check whether found node is good
606  if (!ValidNumber(T[i][j])){
607  // If not, find its nearest good neighbor
608  // (nearest good neighbors are precalculated and cached)
609  std::size_t inew = nearest_neighbor_i[i][j];
610  std::size_t jnew = nearest_neighbor_j[i][j];
611  i = inew; j = jnew;
612  }
613  }
616  void find_native_nearest_good_cell(double x, double y, std::size_t &i, std::size_t &j){
617  bisect_vector(xvec, x, i);
618  bisect_vector(yvec, y, j);
619  }
620  const std::vector<std::vector<double> > & get(parameters key){
621  switch(key){
622  case iDmolar: return rhomolar;
623  case iT: return T;
624  case iUmolar: return umolar;
625  case iHmolar: return hmolar;
626  case iSmolar: return smolar;
627  case iP: return p;
628  case iviscosity: return visc;
629  case iconductivity: return cond;
630  default: throw KeyError(format("invalid key"));
631  }
632  }
633 };
634 
637 {
638  public:
639  LogPHTable(){
640  xkey = iHmolar; ykey = iP; logy = true; logx = false;
641  };
642  void set_limits(){
643  if (this->AS.get() == NULL){
644  throw ValueError("AS is not yet set");
645  }
646  CoolPropDbl Tmin = std::max(AS->Ttriple(), AS->Tmin());
647  // Minimum enthalpy is the saturated liquid enthalpy
648  AS->update(QT_INPUTS, 0, Tmin);
649  xmin = AS->hmolar(); ymin = AS->p();
650 
651  // Check both the enthalpies at the Tmax isotherm to see whether to use low or high pressure
652  AS->update(DmolarT_INPUTS, 1e-10, 1.499*AS->Tmax());
653  CoolPropDbl xmax1 = AS->hmolar();
654  AS->update(PT_INPUTS, AS->pmax(), 1.499*AS->Tmax());
655  CoolPropDbl xmax2 = AS->hmolar();
656  xmax = std::max(xmax1, xmax2);
657 
658  ymax = AS->pmax();
659  }
660  void deserialize(msgpack::object &deserialized){
661  LogPHTable temp;
662  deserialized.convert(temp);
663  temp.unpack();
664  if (Nx != temp.Nx || Ny != temp.Ny)
665  {
666  throw ValueError(format("old [%dx%d] and new [%dx%d] dimensions don't agree", temp.Nx, temp.Ny, Nx, Ny));
667  }
668  else if (revision > temp.revision)
669  {
670  throw ValueError(format("loaded revision [%d] is older than current revision [%d]", temp.revision, revision));
671  }
672  else if ((std::abs(xmin) > 1e-10 && std::abs(xmax) > 1e-10) && (std::abs(temp.xmin - xmin)/xmin > 1e-6 || std::abs(temp.xmax - xmax)/xmax > 1e-6)){
673  throw ValueError(format("Current limits for x [%g,%g] do not agree with loaded limits [%g,%g]", xmin, xmax, temp.xmin, temp.xmax));
674  }
675  else if ((std::abs(ymin) > 1e-10 && std::abs(ymax) > 1e-10) && (std::abs(temp.ymin - ymin)/ymin > 1e-6 || std::abs(temp.ymax - ymax)/ymax > 1e-6)){
676  throw ValueError(format("Current limits for y [%g,%g] do not agree with loaded limits [%g,%g]", ymin, ymax, temp.ymin, temp.ymax));
677  }
678  std::swap(*this, temp); // Swap
679  this->AS = temp.AS; // Reconnect the AbstractState pointer
680  };
681 };
684 {
685  public:
686  LogPTTable(){
687  xkey = iT; ykey = iP; logy = true; logx = false; xmin = _HUGE; ymin = _HUGE; xmax=_HUGE; ymax=_HUGE;
688  };
689  void set_limits(){
690  if (this->AS.get() == NULL){
691  throw ValueError("AS is not yet set");
692  }
693  CoolPropDbl Tmin = std::max(AS->Ttriple(), AS->Tmin());
694  AS->update(QT_INPUTS, 0, Tmin);
695  xmin = Tmin;
696  ymin = AS->p();
697 
698  xmax = AS->Tmax()*1.499; ymax = AS->pmax();
699  }
700  void deserialize(msgpack::object &deserialized){
701  LogPTTable temp;
702  deserialized.convert(temp);
703  temp.unpack();
704  if (Nx != temp.Nx || Ny != temp.Ny)
705  {
706  throw ValueError(format("old [%dx%d] and new [%dx%d] dimensions don't agree",temp.Nx, temp.Ny, Nx, Ny));
707  }
708  else if (revision > temp.revision)
709  {
710  throw ValueError(format("loaded revision [%d] is older than current revision [%d]", temp.revision, revision));
711  }
712  else if ((std::abs(xmin) > 1e-10 && std::abs(xmax) > 1e-10) && (std::abs(temp.xmin - xmin)/xmin > 1e-6 || std::abs(temp.xmax - xmax)/xmax > 1e-6)){
713  throw ValueError(format("Current limits for x [%g,%g] do not agree with loaded limits [%g,%g]", xmin, xmax, temp.xmin, temp.xmax));
714  }
715  else if ((std::abs(ymin) > 1e-10 && std::abs(ymax) > 1e-10) && (std::abs(temp.ymin - ymin)/ymin > 1e-6 || std::abs(temp.ymax - ymax)/ymax > 1e-6)){
716  throw ValueError(format("Current limits for y [%g,%g] do not agree with loaded limits [%g,%g]", ymin, ymax, temp.ymin, temp.ymax));
717  }
718  std::swap(*this, temp); // Swap
719  this->AS = temp.AS; // Reconnect the AbstractState pointer
720  };
721 };
722 
726 private:
727  std::size_t alt_i, alt_j;
728  bool _valid, _has_valid_neighbor;
729 public:
730  double dx_dxhat, dy_dyhat;
731  CellCoeffs(){
732  _valid = false; _has_valid_neighbor = false;
733  dx_dxhat = _HUGE; dy_dyhat = _HUGE;
734  alt_i = 9999999; alt_j = 9999999;
735  }
736  std::vector<double> T, rhomolar, hmolar, p, smolar, umolar;
738  const std::vector<double> & get(const parameters params) const
739  {
740  switch (params){
741  case iT: return T;
742  case iP: return p;
743  case iDmolar: return rhomolar;
744  case iHmolar: return hmolar;
745  case iSmolar: return smolar;
746  case iUmolar: return umolar;
747  default: throw KeyError(format("Invalid key to get() function of CellCoeffs"));
748  }
749  };
751  void set(parameters params, const std::vector<double> &mat){
752  switch (params){
753  case iT: T = mat; break;
754  case iP: p = mat; break;
755  case iDmolar: rhomolar = mat; break;
756  case iHmolar: hmolar = mat; break;
757  case iSmolar: smolar = mat; break;
758  case iUmolar: umolar = mat; break;
759  default: throw KeyError(format("Invalid key to set() function of CellCoeffs"));
760  }
761  };
763  bool valid() const { return _valid; };
765  void set_valid(){ _valid = true; };
767  void set_invalid(){ _valid = false; };
769  void set_alternate(std::size_t i, std::size_t j){ alt_i = i; alt_j = j; _has_valid_neighbor = true; }
771  void get_alternate(std::size_t &i, std::size_t &j) const {
772  if (_has_valid_neighbor){
773  i = alt_i; j = alt_j;
774  }
775  else{
776  throw ValueError("No valid neighbor");
777  }
778  }
780  bool has_valid_neighbor() const{
781  return _has_valid_neighbor;
782  }
783 };
784 
787 {
788 public:
789  bool tables_loaded;
790  LogPHTable single_phase_logph;
791  LogPTTable single_phase_logpT;
792  PureFluidSaturationTableData pure_saturation;
793  PackablePhaseEnvelopeData phase_envelope;
794  std::vector<std::vector<CellCoeffs> > coeffs_ph, coeffs_pT;
795 
796  TabularDataSet(){ tables_loaded = false; }
798  void write_tables(const std::string &path_to_tables);
800  void load_tables(const std::string &path_to_tables, shared_ptr<CoolProp::AbstractState> &AS);
802  void build_tables(shared_ptr<CoolProp::AbstractState> &AS);
804  void build_coeffs(SinglePhaseGriddedTableData &table, std::vector<std::vector<CellCoeffs> > &coeffs);
805 };
806 
808 {
809 private:
810  std::map<std::string, TabularDataSet> data;
811 public:
812  TabularDataLibrary(){};
813  std::string path_to_tables(shared_ptr<CoolProp::AbstractState> &AS){
814  std::vector<std::string> fluids = AS->fluid_names();
815  std::vector<CoolPropDbl> fractions = AS->get_mole_fractions();
816  std::vector<std::string> components;
817  for (std::size_t i = 0; i < fluids.size(); ++i){
818  components.push_back(format("%s[%0.10Lf]", fluids[i].c_str(), fractions[i]));
819  }
820  std::string table_directory = get_home_dir() + "/.CoolProp/Tables/";
821  std::string alt_table_directory = get_config_string(ALTERNATIVE_TABLES_DIRECTORY);
822  if (!alt_table_directory.empty()){
823  table_directory = alt_table_directory;
824  }
825  return table_directory + AS->backend_name() + "(" + strjoin(components, "&") + ")";
826  }
828  TabularDataSet * get_set_of_tables(shared_ptr<AbstractState> &AS, bool &loaded);
829 };
830 
838 {
839  protected:
840  phases imposed_phase_index;
841  bool tables_loaded, using_single_phase_table, is_mixture;
842  enum selected_table_options{SELECTED_NO_TABLE=0, SELECTED_PH_TABLE, SELECTED_PT_TABLE};
843  selected_table_options selected_table;
844  std::size_t cached_single_phase_i, cached_single_phase_j;
845  std::size_t cached_saturation_iL, cached_saturation_iV;
846  std::vector<std::vector<double> > const *z;
847  std::vector<std::vector<double> > const *dzdx;
848  std::vector<std::vector<double> > const *dzdy;
849  std::vector<std::vector<double> > const *d2zdx2;
850  std::vector<std::vector<double> > const *d2zdxdy;
851  std::vector<std::vector<double> > const *d2zdy2;
852  std::vector<CoolPropDbl> mole_fractions;
853  public:
854  shared_ptr<CoolProp::AbstractState> AS;
855  TabularBackend(shared_ptr<CoolProp::AbstractState> AS) : tables_loaded(false), using_single_phase_table(false), is_mixture(false), AS(AS) {
856  selected_table = SELECTED_NO_TABLE;
857  // Flush the cached indices (set to large number)
858  cached_single_phase_i = std::numeric_limits<std::size_t>::max();
859  cached_single_phase_j = std::numeric_limits<std::size_t>::max();
860  cached_saturation_iL = std::numeric_limits<std::size_t>::max();
861  cached_saturation_iV = std::numeric_limits<std::size_t>::max();
862  z = NULL; dzdx = NULL; dzdy = NULL; d2zdx2 = NULL; d2zdxdy = NULL; d2zdy2 = NULL; dataset = NULL;
863  imposed_phase_index = iphase_not_imposed;
864  };
865 
866  // None of the tabular methods are available from the high-level interface
867  bool available_in_high_level(void){return false;}
868 
869  std::string calc_name(void){ return AS->name(); }
870  std::vector<std::string> calc_fluid_names(void){ return AS->fluid_names(); }
871 
872  void connect_pointers(parameters output, const SinglePhaseGriddedTableData &table)
873  {
874  // Connect the pointers based on the output variable desired
875  switch(output){
876  case iT:
877  z = &table.T; dzdx = &table.dTdx; dzdy = &table.dTdy;
878  d2zdxdy = &table.d2Tdxdy; d2zdx2 = &table.d2Tdx2; d2zdy2 = &table.d2Tdy2;
879  break;
880  case iDmolar:
881  z = &table.rhomolar; dzdx = &table.drhomolardx; dzdy = &table.drhomolardy;
882  d2zdxdy = &table.d2rhomolardxdy; d2zdx2 = &table.d2rhomolardx2; d2zdy2 = &table.d2rhomolardy2;
883  break;
884  case iSmolar:
885  z = &table.smolar; dzdx = &table.dsmolardx; dzdy = &table.dsmolardy;
886  d2zdxdy = &table.d2smolardxdy; d2zdx2 = &table.d2smolardx2; d2zdy2 = &table.d2smolardy2;
887  break;
888  case iHmolar:
889  z = &table.hmolar; dzdx = &table.dhmolardx; dzdy = &table.dhmolardy;
890  d2zdxdy = &table.d2hmolardxdy; d2zdx2 = &table.d2hmolardx2; d2zdy2 = &table.d2hmolardy2;
891  break;
892  case iUmolar:
893  z = &table.umolar; dzdx = &table.dumolardx; dzdy = &table.dumolardy;
894  d2zdxdy = &table.d2umolardxdy; d2zdx2 = &table.d2umolardx2; d2zdy2 = &table.d2umolardy2;
895  break;
896  case iviscosity:
897  z = &table.visc; break;
898  case iconductivity:
899  z = &table.cond; break;
900  default:
901  throw ValueError();
902  }
903  }
904  TabularDataSet * dataset;
905 
906  void recalculate_singlephase_phase()
907  {
908  if (p() > p_critical()){
909  if (T() > T_critical()){
910  _phase = iphase_supercritical;
911  }
912  else{
914  }
915  }
916  else{
917  if (T() > T_critical()){
918  _phase = iphase_supercritical_gas;
919  }
920  else{
921  // Liquid or vapor
922  if (rhomolar() > rhomolar_critical()){
923  _phase = iphase_liquid;
924  }
925  else{
926  _phase = iphase_gas;
927  }
928  }
929  }
930  }
935  void calc_specify_phase(phases phase_index){ imposed_phase_index = phase_index; };
936 
939  void calc_unspecify_phase(){ imposed_phase_index = iphase_not_imposed; };
940 
941  virtual double evaluate_single_phase_phmolar(parameters output, std::size_t i, std::size_t j) = 0;
942  virtual double evaluate_single_phase_pT(parameters output, std::size_t i, std::size_t j) = 0;
943  virtual double evaluate_single_phase_phmolar_transport(parameters output, std::size_t i, std::size_t j) = 0;
944  virtual double evaluate_single_phase_pT_transport(parameters output, std::size_t i, std::size_t j) = 0;
945  virtual double evaluate_single_phase_phmolar_derivative(parameters output, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny) = 0;
946  virtual double evaluate_single_phase_pT_derivative(parameters output, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny) = 0;
947 
949  virtual void find_native_nearest_good_indices(SinglePhaseGriddedTableData &table, const std::vector<std::vector<CellCoeffs> > &coeffs, double x, double y, std::size_t &i, std::size_t &j) = 0;
951  virtual void find_nearest_neighbor(SinglePhaseGriddedTableData &table,
952  const std::vector<std::vector<CellCoeffs> > &coeffs,
953  const parameters variable1,
954  const double value1,
955  const parameters other,
956  const double otherval,
957  std::size_t &i,
958  std::size_t &j) = 0;
960  virtual void invert_single_phase_x(const SinglePhaseGriddedTableData &table, const std::vector<std::vector<CellCoeffs> > &coeffs, parameters output, double x, double y, std::size_t i, std::size_t j) = 0;
962  virtual void invert_single_phase_y(const SinglePhaseGriddedTableData &table, const std::vector<std::vector<CellCoeffs> > &coeffs, parameters output, double x, double y, std::size_t i, std::size_t j) = 0;
963 
964 
965  phases calc_phase(void){ return _phase; }
966  CoolPropDbl calc_T_critical(void){return this->AS->T_critical();};
967  CoolPropDbl calc_Ttriple(void){return this->AS->Ttriple();};
968  CoolPropDbl calc_p_triple(void){return this->AS->p_triple();};
969  CoolPropDbl calc_pmax(void){return this->AS->pmax();};
970  CoolPropDbl calc_Tmax(void){return this->AS->Tmax();};
971  CoolPropDbl calc_Tmin(void){return this->AS->Tmin();};
972  CoolPropDbl calc_p_critical(void){ return this->AS->p_critical(); }
973  CoolPropDbl calc_rhomolar_critical(void){ return this->AS->rhomolar_critical(); }
974  bool using_mole_fractions(void){return true;}
975  bool using_mass_fractions(void){return false;}
976  bool using_volu_fractions(void){return false;}
977  void update(CoolProp::input_pairs input_pair, double Value1, double Value2);
978  void set_mole_fractions(const std::vector<CoolPropDbl> &mole_fractions){this->AS->set_mole_fractions(mole_fractions);};
979  void set_mass_fractions(const std::vector<CoolPropDbl> &mass_fractions){ throw NotImplementedError("set_mass_fractions not implemented for Tabular backends"); };
980  const std::vector<CoolPropDbl> & get_mole_fractions(){return AS->get_mole_fractions();};
981  const std::vector<CoolPropDbl> calc_mass_fractions(void){ return AS->get_mass_fractions(); };
982 
983  CoolPropDbl calc_molar_mass(void){return AS->molar_mass();};
984 
985  CoolPropDbl calc_saturated_liquid_keyed_output(parameters key);
986  CoolPropDbl calc_saturated_vapor_keyed_output(parameters key);
987 
989  std::string path_to_tables(void);
991  void load_tables();
992  void pack_matrices(){
993  PackablePhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
994  PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
995  SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
996  SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
997  single_phase_logph.pack();
998  single_phase_logpT.pack();
999  pure_saturation.pack();
1000  phase_envelope.pack();
1001  }
1003  void write_tables();
1004 
1005  CoolPropDbl phase_envelope_sat(const PhaseEnvelopeData &env, parameters output, parameters iInput1, double value1){
1006  const PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
1007  CoolPropDbl yL = PhaseEnvelopeRoutines::evaluate(phase_envelope, output, iInput1, value1, cached_saturation_iL);
1008  CoolPropDbl yV = PhaseEnvelopeRoutines::evaluate(phase_envelope, output, iInput1, value1, cached_saturation_iV);
1009  return _Q*yV + (1-_Q)*yL;
1010  }
1011  CoolPropDbl calc_cpmolar_idealgas(void){
1012  this->AS->set_T(_T);
1013  return this->AS->cp0molar();
1014  }
1016  CoolPropDbl calc_surface_tension(void){
1017  this->AS->set_T(_T);
1018  return this->AS->surface_tension();
1019  this->AS->set_T(_HUGE);
1020  }
1021  CoolPropDbl calc_p(void);
1022  CoolPropDbl calc_T(void);
1023  CoolPropDbl calc_rhomolar(void);
1024  CoolPropDbl calc_hmolar(void);
1025  CoolPropDbl calc_smolar(void);
1026  CoolPropDbl calc_umolar(void);
1027  CoolPropDbl calc_cpmolar(void);
1028  CoolPropDbl calc_cvmolar(void);
1029  CoolPropDbl calc_viscosity(void);
1030  CoolPropDbl calc_conductivity(void);
1032  CoolPropDbl calc_speed_sound(void);
1033  CoolPropDbl calc_first_partial_deriv(parameters Of, parameters Wrt, parameters Constant);
1036  CoolPropDbl calc_first_saturation_deriv(parameters Of1, parameters Wrt1);
1037  CoolPropDbl calc_first_two_phase_deriv(parameters Of, parameters Wrt, parameters Constant);
1038 
1040  CoolPropDbl calc_first_two_phase_deriv_splined(parameters Of, parameters Wrt, parameters Constant, CoolPropDbl x_end);
1041 
1043  if (!tables_loaded){
1044  try{
1046  load_tables();
1047  // Set the flag saying tables have been successfully loaded
1048  tables_loaded = true;
1049  }
1050  catch(CoolProp::UnableToLoadError &e){
1051  if (get_debug_level() > 0){ std::cout << format("Table loading failed with error: %s\n", e.what()); }
1053  std::string table_path = path_to_tables();
1054  #if defined(__ISWINDOWS__)
1055  double directory_size_in_GB = CalculateDirSize(std::wstring(table_path.begin(), table_path.end()))/POW3(1024.0);
1056  #else
1057  double directory_size_in_GB = CalculateDirSize(table_path)/POW3(1024.0);
1058  #endif
1059  double allowed_size_in_GB = get_config_double(MAXIMUM_TABLE_DIRECTORY_SIZE_IN_GB);
1060  if (get_debug_level() > 0){std::cout << "Tabular directory size is " << directory_size_in_GB << " GB\n";}
1061  if (directory_size_in_GB > 1.5*allowed_size_in_GB){
1062  throw DirectorySizeError(format("Maximum allowed tabular directory size is %g GB, you have exceeded 1.5 times this limit", allowed_size_in_GB));
1063  }
1064  else if (directory_size_in_GB > allowed_size_in_GB){
1065  set_warning_string(format("Maximum allowed tabular directory size is %g GB, you have exceeded this limit", allowed_size_in_GB));
1066  }
1068  dataset->build_tables(this->AS);
1069  pack_matrices();
1070  write_tables();
1072  load_tables();
1073  // Set the flag saying tables have been successfully loaded
1074  tables_loaded = true;
1075  }
1076  }
1077  };
1078 };
1079 
1080 
1081 } /* namespace CoolProp*/
1082 
1083 #endif
Mass-based internal energy.
Definition: DataStructures.h:100
void pack()
Take all the vectors that are in the class and pack them into the vectors map for easy unpacking usin...
Definition: TabularBackends.h:270
void resize(std::size_t N)
Resize all the vectors.
Definition: TabularBackends.h:263
Supercritical liquid (p > pc, T < Tc)
Definition: DataStructures.h:161
This class holds the data for a two-phase table that is log spaced in p.
Definition: TabularBackends.h:140
std::vector< std::string > calc_fluid_names(void)
Using this backend, get a vector of fluid names.
Definition: TabularBackends.h:870
void calc_specify_phase(phases phase_index)
Specify the phase - this phase will always be used in calculations.
Definition: TabularBackends.h:935
void make_axis_vectors(void)
Make vectors for the x-axis values and the y-axis values.
Definition: TabularBackends.h:478
const std::vector< CoolPropDbl > & get_mole_fractions()
Get the mole fractions of the fluid.
Definition: TabularBackends.h:980
Molar density in mol/m^3, Temperature in K.
Definition: DataStructures.h:230
void unpack()
Take all the matrices that are in the class and pack them into the matrices map for easy unpacking us...
Definition: TabularBackends.h:533
void calc_unspecify_phase()
Unspecify the phase - the phase is no longer imposed, different solvers can do as they like...
Definition: TabularBackends.h:939
Mass-based enthalpy.
Definition: DataStructures.h:95
void check_tables()
Definition: TabularBackends.h:1042
CoolPropDbl calc_Tmax(void)
Using this backend, calculate the maximum temperature in K.
Definition: TabularBackends.h:970
This structure holds the coefficients for one cell, the coefficients are stored in matrices and can b...
Definition: TabularBackends.h:725
Subcritical liquid.
Definition: DataStructures.h:158
Supercritical gas (p < pc, T > Tc)
Definition: DataStructures.h:160
double get_config_double(configuration_keys key)
Return the value of a double configuration key.
Definition: Configuration.cpp:92
CoolPropDbl calc_cpmolar_idealgas(void)
Using this backend, calculate the ideal gas molar constant-pressure specific heat in J/mol/K...
Definition: TabularBackends.h:1011
void make_good_neighbors(void)
Make matrices of good neighbors if the current value for i,j corresponds to a bad node...
Definition: TabularBackends.h:493
phases
These are constants for the phases of the fluid.
Definition: DataStructures.h:158
This class contains the data for one set of Tabular data including single-phase and two-phase data...
Definition: TabularBackends.h:786
void find_nearest_neighbor(parameters givenkey, double givenval, parameters otherkey, double otherval, std::size_t &i, std::size_t &j)
Find the nearest neighbor for one (given) variable native, one variable non-native.
Definition: TabularBackends.h:571
void resize(std::size_t Nx, std::size_t Ny)
Resize all the matrices.
Definition: TabularBackends.h:470
int get_debug_level()
Get the debug level.
Definition: CoolProp.cpp:63
Mass-based density.
Definition: DataStructures.h:94
void set_warning_string(const std::string &warning)
An internal function to set the global warning string.
Definition: CoolProp.cpp:69
std::string get_config_string(configuration_keys key)
Return the value of a string configuration key.
Definition: Configuration.cpp:95
std::vector< std::vector< double > > mat
This class implements bicubic interpolation, as very clearly laid out by the page on wikipedia: http:...
Definition: BicubicBackend.h:64
void set_invalid()
Call this function to set the valid flag to false.
Definition: TabularBackends.h:767
Definition: TabularBackends.h:807
This class holds the single-phase data for a log(p)-T gridded table.
Definition: TabularBackends.h:683
bool available_in_high_level(void)
A function that says whether the backend instance can be instantiated in the high-level interface In ...
Definition: TabularBackends.h:867
Mole-based constant-volume specific heat.
Definition: DataStructures.h:85
Pressure in Pa, Temperature in K.
Definition: DataStructures.h:227
The mother of all state classes.
Definition: AbstractState.h:70
CoolPropDbl calc_molar_mass(void)
Using this backend, calculate the molar mass in kg/mol.
Definition: TabularBackends.h:983
CoolPropDbl calc_T_critical(void)
Using this backend, get the critical point temperature in K.
Definition: TabularBackends.h:966
Isobaric expansion coefficient.
Definition: DataStructures.h:113
void pack()
Take all the matrices that are in the class and pack them into the matrices map for easy unpacking us...
Definition: TabularBackends.h:519
A data structure to hold the data for a phase envelope.
Definition: PhaseEnvelope.h:14
phases calc_phase(void)
Using this backend, calculate the phase.
Definition: TabularBackends.h:965
void build_tables(shared_ptr< CoolProp::AbstractState > &AS)
Build the tables (single-phase PH, single-phase PT, phase envelope, etc.)
Definition: TabularBackends.cpp:1239
CoolPropDbl calc_surface_tension(void)
Calculate the surface tension using the wrapped class (fast enough)
Definition: TabularBackends.h:1016
void get_alternate(std::size_t &i, std::size_t &j) const
Get neighboring(alternate) cell to be used if this cell is invalid.
Definition: TabularBackends.h:771
input_pairs
These are input pairs that can be used for the update function (in each pair, input keys are sorted a...
Definition: DataStructures.h:216
bool has_valid_neighbor() const
Returns true if cell is invalid and it has valid neighbor.
Definition: TabularBackends.h:780
Subcritical gas.
Definition: DataStructures.h:163
Definition: Exceptions.h:26
This class holds the data for a single-phase interpolation table that is regularly spaced...
Definition: TabularBackends.h:439
Mass-based constant-volume specific heat.
Definition: DataStructures.h:99
void set_valid()
Call this function to set the valid flag to true.
Definition: TabularBackends.h:765
Definition: TabularBackends.h:28
Molar quality, Temperature in K.
Definition: DataStructures.h:218
CoolPropDbl calc_pmax(void)
Using this backend, calculate the maximum pressure in Pa.
Definition: TabularBackends.h:969
Mass-based entropy.
Definition: DataStructures.h:96
Viscosity.
Definition: DataStructures.h:105
std::string calc_name(void)
Using this backend, get the name of the fluid.
Definition: TabularBackends.h:869
Mole-based density.
Definition: DataStructures.h:80
This class holds the single-phase data for a log(p)-h gridded table.
Definition: TabularBackends.h:636
Mole-based constant-pressure specific heat.
Definition: DataStructures.h:83
Mole-based entropy.
Definition: DataStructures.h:82
CoolPropDbl calc_rhomolar_critical(void)
Using this backend, get the critical point molar density in mol/m^3.
Definition: TabularBackends.h:973
Pressure.
Definition: DataStructures.h:74
CoolPropDbl calc_Tmin(void)
Using this backend, calculate the minimum temperature in K.
Definition: TabularBackends.h:971
Speed of sound.
Definition: DataStructures.h:111
Isothermal compressibility.
Definition: DataStructures.h:112
CoolPropDbl calc_p_critical(void)
Using this backend, get the critical point pressure in Pa.
Definition: TabularBackends.h:972
void unpack()
Take all the vectors that are in the class and unpack them from the vectors map.
Definition: TabularBackends.h:284
void set_alternate(std::size_t i, std::size_t j)
Set the neighboring (alternate) cell to be used if the cell is invalid.
Definition: TabularBackends.h:769
bool valid() const
Returns true if the cell coefficients seem to have been calculated properly.
Definition: TabularBackends.h:763
void find_native_nearest_good_neighbor(double x, double y, std::size_t &i, std::size_t &j)
Find the nearest good neighbor node for inputs that are the same as the grid inputs If the straightfo...
Definition: TabularBackends.h:602
Thermal conductivity.
Definition: DataStructures.h:106
void pack()
Take all the vectors that are in the class and pack them into the vectors map for easy unpacking usin...
Definition: TabularBackends.h:53
Mole-based internal energy.
Definition: DataStructures.h:86
std::size_t ipsat_max
The index of the point corresponding to the maximum pressure for Type-I mixtures. ...
Definition: PhaseEnvelope.h:19
CoolPropDbl calc_Ttriple(void)
Using this backend, get the triple point temperature in K.
Definition: TabularBackends.h:967
CoolPropDbl calc_p_triple(void)
Using this backend, get the triple point pressure in Pa.
Definition: TabularBackends.h:968
std::size_t iTsat_max
The index of the point corresponding to the maximum temperature for Type-I mixtures.
Definition: PhaseEnvelope.h:19
double first_saturation_deriv(parameters Of1, parameters Wrt1, int Q, double val, std::size_t i)
Calculate the first derivative ALONG a saturation curve.
Definition: TabularBackends.h:404
This class contains the general code for tabular backends (TTSE, bicubic, etc.)
Definition: TabularBackends.h:837
bool native_inputs_are_in_range(double x, double y)
Check that the native inputs (the inputs the table is based on) are in range.
Definition: TabularBackends.h:543
void unpack()
Take all the vectors that are in the class and unpack them from the vectors map.
Definition: TabularBackends.h:78
Supercritical (p > pc, T > Tc)
Definition: DataStructures.h:159
This file contains flash routines in which the state is unknown, and a solver of some kind must be us...
Definition: AbstractState.h:19
void mass_to_molar(parameters &param, double &conversion_factor, double molar_mass)
Get a conversion factor from mass to molar if needed.
Definition: TabularBackends.h:108
void find_native_nearest_good_cell(double x, double y, std::size_t &i, std::size_t &j)
Find the nearest cell with lower left coordinate (i,j) where (i,j) is a good node, and so are (i+1,j), (i,j+1), (i+1,j+1) This is needed for bicubic interpolation.
Definition: TabularBackends.h:616
parameters
Define some constants that will be used throughout These are constants for the input and output para...
Definition: DataStructures.h:49
Mole-based enthalpy.
Definition: DataStructures.h:81
Temperature.
Definition: DataStructures.h:73
Mass-based constant-pressure specific heat.
Definition: DataStructures.h:97
void find_native_nearest_neighbor(double x, double y, std::size_t &i, std::size_t &j)
Find the nearest neighbor for native inputs (the inputs the table is based on) Does not check whether...
Definition: TabularBackends.h:550
Vapor quality.
Definition: DataStructures.h:75