/** Use the single_phase table to evaluate an output for a transport property * * Here we use bilinear interpolation because we don't have any information about the derivatives with respect to the * independent variables and it is too computationally expensive to build the derivatives numerically * * See also http://en.wikipedia.org/wiki/Bilinear_interpolation#Nonlinear */ double CoolProp::TTSEBackend::evaluate_single_phase_transport(SinglePhaseGriddedTableData &table, parameters output, double x, double y, std::size_t i, std::size_t j) { bool in_bounds = (i < table.xvec.size()-1 && j < table.yvec.size()-1); if (!in_bounds){ throw ValueError("Cell to TTSEBackend::evaluate_single_phase_transport is not valid"); } bool is_valid = (ValidNumber(table.smolar[i][j]) && ValidNumber(table.smolar[i+1][j]) && ValidNumber(table.smolar[i][j+1]) && ValidNumber(table.smolar[i+1][j+1])); if (!is_valid){ throw ValueError("Cell to TTSEBackend::evaluate_single_phase_transport must have four valid corners for now"); } const std::vector<std::vector<double> > &f = table.get(output); double x1 = table.xvec[i], x2 = table.xvec[i+1], y1 = table.yvec[j], y2 = table.yvec[j+1]; double f11 = f[i][j], f12 = f[i][j+1], f21 = f[i+1][j], f22 = f[i+1][j+1]; double val = 1/((x2-x1)*(y2-y1))*( f11*(x2 - x)*(y2 - y) +f21*(x - x1)*(y2 - y) +f12*(x2 - x)*(y - y1) +f22*(x - x1)*(y - y1)); // Cache the output value calculated switch(output){ case iconductivity: _conductivity = val; break; case iviscosity: _viscosity = val; break; default: throw ValueError(); } return val; }
void JSONFluidLibrary::set_fluid_enthalpy_entropy_offset(const std::string &fluid, double delta_a1, double delta_a2, const std::string &ref) { // Try to find it std::map<std::string, std::size_t>::const_iterator it = string_to_index_map.find(fluid); if (it != string_to_index_map.end()){ std::map<std::size_t, CoolPropFluid>::iterator it2 = fluid_map.find(it->second); // If it is found if (it2 != fluid_map.end()){ if (!ValidNumber(delta_a1) || !ValidNumber(delta_a2) ){ throw ValueError(format("Not possible to set reference state for fluid %s because offset values are NAN",fluid.c_str())); } it2->second.EOS().alpha0.EnthalpyEntropyOffset.set(delta_a1, delta_a2, ref); shared_ptr<CoolProp::HelmholtzEOSBackend> HEOS(new CoolProp::HelmholtzEOSBackend(it2->second)); // Calculate the new enthalpy and entropy values HEOS->update(DmolarT_INPUTS, it2->second.EOS().hs_anchor.rhomolar, it2->second.EOS().hs_anchor.T); it2->second.EOS().hs_anchor.hmolar = HEOS->hmolar(); it2->second.EOS().hs_anchor.smolar = HEOS->smolar(); // Calculate the new enthalpy and entropy values at the reducing stat HEOS->update(DmolarT_INPUTS, it2->second.EOS().reduce.rhomolar, it2->second.EOS().reduce.T); it2->second.EOS().reduce.hmolar = HEOS->hmolar(); it2->second.EOS().reduce.smolar = HEOS->smolar(); } else{ throw ValueError(format("fluid [%s] was not found in JSONFluidLibrary",fluid.c_str())); } } }
CScValue* CSXArray::ScGetProperty(char *Name) { m_ScValue->SetNULL(); ////////////////////////////////////////////////////////////////////////// // Type ////////////////////////////////////////////////////////////////////////// if(strcmp(Name, "Type")==0){ m_ScValue->SetString("array"); return m_ScValue; } ////////////////////////////////////////////////////////////////////////// // Length ////////////////////////////////////////////////////////////////////////// else if(strcmp(Name, "Length")==0){ m_ScValue->SetInt(m_Length); return m_ScValue; } ////////////////////////////////////////////////////////////////////////// // [number] ////////////////////////////////////////////////////////////////////////// else{ char ParamName[20]; if(ValidNumber(Name, ParamName)){ return m_Values->GetProp(ParamName); } else return m_ScValue; } }
double Props1SI(const std::string &FluidName, const std::string &Output) { std::string _FluidName = FluidName, empty_string = "", _Output = Output; double val1 = PropsSI(_FluidName, empty_string, 0, empty_string, 0, _Output); if (!ValidNumber(val1)){ // flush the error set_error_string(""); // Try with them flipped val1 = PropsSI(_Output, empty_string, 0, empty_string, 0, _FluidName); } if (!ValidNumber(val1)){ set_error_string(format("Unable to use inputs %s,%s in Props1SI (order doesn't matter)")); return _HUGE; } return val1; }
std::string PhaseSI(const std::string &Name1, double Prop1, const std::string &Name2, double Prop2, const std::string &FluidName, const std::vector<double> &z) { double Phase_double = PropsSI("Phase",Name1,Prop1,Name2,Prop2,FluidName,z); if (!ValidNumber(Phase_double)){ return "";} std::size_t Phase_int = static_cast<std::size_t>(Phase_double); return phase_lookup_string(static_cast<phases>(Phase_int)); }
/** In the newton function, a 1-D Newton-Raphson solver is implemented using exact solutions. An initial guess for the solution is provided. @param f A pointer to an instance of the FuncWrapper1D class that implements the call() function @param x0 The inital guess for the solution @param ftol The absolute value of the tolerance accepted for the objective function @param maxiter Maximum number of iterations @returns If no errors are found, the solution, otherwise the value _HUGE, the value for infinity */ double Newton(FuncWrapper1DWithDeriv* f, double x0, double ftol, int maxiter) { double x, dx, fval=999; int iter=1; f->errstring.clear(); x = x0; while (iter < 2 || std::abs(fval) > ftol) { fval = f->call(x); dx = -fval/f->deriv(x); if (!ValidNumber(fval)){ throw ValueError("Residual function in newton returned invalid number"); }; x += dx; if (std::abs(dx/x) < 1e-11){ return x; } if (iter>maxiter) { f->errstring= "reached maximum number of iterations"; throw SolutionError(format("Newton reached maximum number of iterations")); } iter=iter+1; } return x; }
HRESULT CSXArray::ScSetProperty(char *Name, CScValue *Value) { ////////////////////////////////////////////////////////////////////////// // Length ////////////////////////////////////////////////////////////////////////// if(strcmp(Name, "Length")==0){ int OrigLength = m_Length; m_Length = max(Value->GetInt(0), 0); char PropName[20]; if(m_Length < OrigLength){ for(int i=m_Length; i<OrigLength; i++){ sprintf(PropName, "%d", i); m_Values->DeleteProp(PropName); } } return S_OK; } ////////////////////////////////////////////////////////////////////////// // [number] ////////////////////////////////////////////////////////////////////////// else{ char ParamName[20]; if(ValidNumber(Name, ParamName)){ int Index = atoi(ParamName); if(Index>=m_Length) m_Length = Index + 1; return m_Values->SetProp(ParamName, Value); } else return E_FAIL; } }
/** In the secant function, a 1-D Newton-Raphson solver is implemented. An initial guess for the solution is provided. @param f A pointer to an instance of the FuncWrapper1D class that implements the call() function @param x0 The inital guess for the solutionh @param dx The initial amount that is added to x in order to build the numerical derivative @param tol The absolute value of the tolerance accepted for the objective function @param maxiter Maximum number of iterations @returns If no errors are found, the solution, otherwise the value _HUGE, the value for infinity */ double Secant(FuncWrapper1D* f, double x0, double dx, double tol, int maxiter) { #if defined(COOLPROP_DEEP_DEBUG) static std::vector<double> xlog, flog; xlog.clear(); flog.clear(); #endif double x1=0,x2=0,x3=0,y1=0,y2=0,x,fval=999; int iter=1; f->errstring.clear(); if (std::abs(dx)==0){ f->errstring="dx cannot be zero"; return _HUGE;} while (iter<=2 || std::abs(fval)>tol) { if (iter==1){x1=x0; x=x1;} if (iter==2){x2=x0+dx; x=x2;} if (iter>2) {x=x2;} if (f->input_not_in_range(x)){ throw ValueError(format("Input [%g] is out of range",x)); } fval = f->call(x); #if defined(COOLPROP_DEEP_DEBUG) xlog.push_back(x); flog.push_back(fval); #endif if (!ValidNumber(fval)){ throw ValueError("Residual function in secant returned invalid number"); }; if (iter==1){y1=fval;} if (iter>1) { double deltax = x2-x1; if (std::abs(deltax)<1e-14){ return x; } y2=fval; double deltay = y2-y1; if (iter > 2 && std::abs(deltay)<1e-14){ return x; } x3=x2-y2/(y2-y1)*(x2-x1); y1=y2; x1=x2; x2=x3; } if (iter>maxiter) { f->errstring=std::string("reached maximum number of iterations"); throw SolutionError(format("Secant reached maximum number of iterations")); } iter=iter+1; } return x3; }
// All the function interfaces that point to the single-input Props function EXPORT_CODE double CONVENTION Props1(const char *FluidName, const char *Output){ fpu_reset_guard guard; double val = Props1SI(Output, FluidName); if (!ValidNumber(val)) // Error code was already set in Props1SI return val; // val is valid; so, Output is already checked in Props1SI -> get_parameter_index won't throw CoolProp::parameters iOutput = CoolProp::get_parameter_index(Output); return convert_from_SI_to_kSI(iOutput, val); }
/** In the Halley's method solver, two derivatives of the input variable are needed, it yields the following method: \f[ x_{n+1} = x_n - \frac {2 f(x_n) f'(x_n)} {2 {[f'(x_n)]}^2 - f(x_n) f''(x_n)} \f] http://en.wikipedia.org/wiki/Halley%27s_method @param f A pointer to an instance of the FuncWrapper1DWithTwoDerivs class that implements the call() and two derivatives @param x0 The inital guess for the solution @param ftol The absolute value of the tolerance accepted for the objective function @param maxiter Maximum number of iterations @returns If no errors are found, the solution, otherwise the value _HUGE, the value for infinity */ double Halley(FuncWrapper1DWithTwoDerivs* f, double x0, double ftol, int maxiter) { double x, dx, fval=999, dfdx, d2fdx2; int iter=1; f->errstring.clear(); x = x0; while (iter < 2 || std::abs(fval) > ftol) { fval = f->call(x); dfdx = f->deriv(x); d2fdx2 = f->second_deriv(x); if (f->input_not_in_range(x)){ throw ValueError(format("Input [%g] is out of range",x)); } if (!ValidNumber(fval)){ throw ValueError("Residual function in Halley returned invalid number"); }; if (!ValidNumber(dfdx)){ throw ValueError("Derivative function in Halley returned invalid number"); }; dx = -(2*fval*dfdx)/(2*POW2(dfdx)-fval*d2fdx2); x += dx; if (std::abs(dx/x) < 10*DBL_EPSILON){ return x; } if (iter>maxiter){ f->errstring= "reached maximum number of iterations"; throw SolutionError(format("Halley reached maximum number of iterations")); } iter=iter+1; } return x; }
// Note: the phase input is currently not supported void CoolPropSolver::setState_ph(double &p, double &h, int &phase, ExternalThermodynamicState *const properties){ if (debug_level > 5) std::cout << format("setState_ph(p=%0.16e,h=%0.16e)\n",p,h); //this->preStateChange(); try{ // Update the internal variables in the state instance state->update(CoolProp::HmassP_INPUTS,h,p); if (!ValidNumber(state->rhomass()) || !ValidNumber(state->T())) { throw CoolProp::ValueError(format("p-h [%g, %g] failed for update",p,h)); } // Set the values in the output structure this->postStateChange(properties); } catch(std::exception &e) { errorMessage((char*)e.what()); } }
void IncompressibleBackend::update(CoolProp::input_pairs input_pair, double value1, double value2) { //if (mass_fractions.empty()){ // throw ValueError("mass fractions have not been set"); //} if (get_debug_level()>=10) { //throw ValueError(format("%s (%d): You have to provide a dimension, 0 or 1, for the solver, %d is not valid. ",__FILE__,__LINE__,axis)); std::cout << format("Incompressible backend: Called update with %d and %f, %f ",input_pair, value1, value2) << std::endl; } clear(); if (get_debug_level()>=50) std::cout << format("Incompressible backend: _fractions are %s ",vec_to_string(_fractions).c_str()) << std::endl; if (fluid->is_pure()){ this->_fluid_type = FLUID_TYPE_INCOMPRESSIBLE_LIQUID; if (get_debug_level()>=50) std::cout << format("Incompressible backend: Fluid type is %d ",this->_fluid_type) << std::endl; if ((_fractions.size()!=1) || (_fractions[0]!=0.0)){ throw ValueError(format("%s is a pure fluid. The composition has to be set to a vector with one entry equal to 0.0 or nothing. %s is not valid.",this->name().c_str(),vec_to_string(_fractions).c_str())); } } else { this->_fluid_type = FLUID_TYPE_INCOMPRESSIBLE_SOLUTION; if (get_debug_level()>=50) std::cout << format("Incompressible backend: Fluid type is %d ",this->_fluid_type) << std::endl; if (_fractions.size()!=1 || ((_fractions[0]<0.0) || (_fractions[0]>1.0)) ){ throw ValueError(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.",this->name().c_str(),vec_to_string(_fractions).c_str())); } } this->_phase = iphase_liquid; if (get_debug_level()>=50) std::cout << format("Incompressible backend: Phase type is %d ",this->_phase) << std::endl; switch (input_pair) { case PT_INPUTS: { _p = value1; _T = value2; break; } case DmassP_INPUTS: { _p = value2; _T = this->DmassP_flash(value1,value2); break; } case PUmass_INPUTS: { _p = value1; _T = this->PUmass_flash(value1, value2); break; } case PSmass_INPUTS: { _p = value1; _T = this->PSmass_flash(value1, value2); break; } case HmassP_INPUTS: { _p = value2; _T = this->HmassP_flash(value1, value2); break; } case QT_INPUTS: { if (value1!=0) {throw ValueError("Incompressible fluids can only handle saturated liquid, Q=0.");} _T = value2; _p = fluid->psat(value2, _fractions[0]); break; } default: { throw ValueError( format("This pair of inputs [%s] is not yet supported", get_input_pair_short_desc(input_pair).c_str())); } } if (_p < 0){ throw ValueError("p is less than zero");} if (!ValidNumber(_p)){ throw ValueError("p is not a valid number");} if (_T < 0){ throw ValueError("T is less than zero");} if (!ValidNumber(_T)){ throw ValueError("T is not a valid number");} if (get_debug_level()>=50) std::cout << format("Incompressible backend: Update finished T=%f, p=%f, x=%s ",this->_T,this->_p,vec_to_string(_fractions).c_str()) << std::endl; fluid->checkTPX(_T,_p,_fractions[0]); }
#if defined (PROPSSI_ERROR_STDOUT) std::cout << e.what() << std::endl; #endif if (get_debug_level() > 1){std::cout << e.what() << std::endl;} return _HUGE; } catch(...){ return _HUGE; } #endif } #if defined(ENABLE_CATCH) TEST_CASE("Check inputs to PropsSI","[PropsSI]") { SECTION("Single state, single output"){ CHECK(ValidNumber(CoolProp::PropsSI("T","P",101325,"Q",0,"Water"))); }; SECTION("Single state, single output, saturation derivative"){ CHECK(ValidNumber(CoolProp::PropsSI("d(P)/d(T)|sigma","P",101325,"Q",0,"Water"))); }; SECTION("Single state, single output, pure incompressible"){ CHECK(ValidNumber(CoolProp::PropsSI("D","P",101325,"T",300,"INCOMP::DowQ"))); }; SECTION("Single state, trivial output, pure incompressible"){ CHECK(ValidNumber(CoolProp::PropsSI("Tmin","P",0,"T",0,"INCOMP::DowQ"))); }; SECTION("Bad input pair"){ CHECK(!ValidNumber(CoolProp::PropsSI("D","Q",0,"Q",0,"Water"))); }; SECTION("Single state, single output, 40% incompressible"){ CHECK(ValidNumber(CoolProp::PropsSI("D","P",101325,"T",300,"INCOMP::MEG[0.40]")));
/** This function implements a 1-D bounded solver using the algorithm from Brent, R. P., Algorithms for Minimization Without Derivatives. Englewood Cliffs, NJ: Prentice-Hall, 1973. Ch. 3-4. a and b must bound the solution of interest and f(a) and f(b) must have opposite signs. If the function is continuous, there must be at least one solution in the interval [a,b]. @param f A pointer to an instance of the FuncWrapper1D class that must implement the class() function @param a The minimum bound for the solution of f=0 @param b The maximum bound for the solution of f=0 @param macheps The machine precision @param t Tolerance (absolute) @param maxiter Maximum numer of steps allowed. Will throw a SolutionError if the solution cannot be found */ double Brent(FuncWrapper1D* f, double a, double b, double macheps, double t, int maxiter) { int iter; f->errstring.clear(); double fa,fb,c,fc,m,tol,d,e,p,q,s,r; fa = f->call(a); fb = f->call(b); // If one of the boundaries is to within tolerance, just stop if (std::abs(fb) < t) { return b;} if (!ValidNumber(fb)){ throw ValueError(format("Brent's method f(b) is NAN for b = %g, other input was a = %g",b,a).c_str()); } if (std::abs(fa) < t) { return a;} if (!ValidNumber(fa)){ throw ValueError(format("Brent's method f(a) is NAN for a = %g, other input was b = %g",a,b).c_str()); } if (fa*fb>0){ throw ValueError(format("Inputs in Brent [%f,%f] do not bracket the root. Function values are [%f,%f]",a,b,fa,fb)); } c=a; fc=fa; iter=1; if (std::abs(fc)<std::abs(fb)){ // Goto ext: from Brent ALGOL code a=b; b=c; c=a; fa=fb; fb=fc; fc=fa; } d=b-a; e=b-a; m=0.5*(c-b); tol=2*macheps*std::abs(b)+t; while (std::abs(m)>tol && fb!=0){ // See if a bisection is forced if (std::abs(e)<tol || std::abs(fa) <= std::abs(fb)){ m=0.5*(c-b); d=e=m; } else{ s=fb/fa; if (a==c){ //Linear interpolation p=2*m*s; q=1-s; } else{ //Inverse quadratic interpolation q=fa/fc; r=fb/fc; m=0.5*(c-b); p=s*(2*m*q*(q-r)-(b-a)*(r-1)); q=(q-1)*(r-1)*(s-1); } if (p>0){ q=-q; } else{ p=-p; } s=e; e=d; m=0.5*(c-b); if (2*p<3*m*q-std::abs(tol*q) || p<std::abs(0.5*s*q)){ d=p/q; } else{ m=0.5*(c-b); d=e=m; } } a=b; fa=fb; if (std::abs(d)>tol){ b+=d; } else if (m>0){ b+=tol; } else{ b+=-tol; } fb=f->call(b); if (!ValidNumber(fb)){ throw ValueError(format("Brent's method f(t) is NAN for t = %g",b).c_str()); } if (std::abs(fb) < macheps){ return b; } if (fb*fc>0){ // Goto int: from Brent ALGOL code c=a; fc=fa; d=e=b-a; } if (std::abs(fc)<std::abs(fb)){ // Goto ext: from Brent ALGOL code a=b; b=c; c=a; fa=fb; fb=fc; fc=fa; } m=0.5*(c-b); tol=2*macheps*std::abs(b)+t; iter+=1; if (!ValidNumber(a)){ throw ValueError(format("Brent's method a is NAN").c_str());} if (!ValidNumber(b)){ throw ValueError(format("Brent's method b is NAN").c_str());} if (!ValidNumber(c)){ throw ValueError(format("Brent's method c is NAN").c_str());} if (iter>maxiter){ throw SolutionError(format("Brent's method reached maximum number of steps of %d ", maxiter));} if (std::abs(fb)< 2*macheps*std::abs(b)){ return b; } } return b; }
void CoolProp::BicubicBackend::build_coeffs(SinglePhaseGriddedTableData &table, std::vector<std::vector<CellCoeffs> > &coeffs) { if (!coeffs.empty()){ return; } const bool debug = get_debug_level() > 5 || false; const int param_count = 6; parameters param_list[param_count] = {iDmolar, iT, iSmolar, iHmolar, iP, iUmolar}; std::vector<std::vector<double> > *f = NULL, *fx = NULL, *fy = NULL, *fxy = NULL; clock_t t1 = clock(); // Resize the coefficient structures coeffs.resize(table.Nx - 1, std::vector<CellCoeffs>(table.Ny - 1)); int valid_cell_count = 0; for (std::size_t k = 0; k < param_count; ++k){ parameters param = param_list[k]; if (param == table.xkey || param == table.ykey){continue;} // Skip tables that match either of the input variables switch(param){ case iT: f = &(table.T); fx = &(table.dTdx); fy = &(table.dTdy); fxy = &(table.d2Tdxdy); break; case iP: f = &(table.p); fx = &(table.dpdx); fy = &(table.dpdy); fxy = &(table.d2pdxdy); break; case iDmolar: f = &(table.rhomolar); fx = &(table.drhomolardx); fy = &(table.drhomolardy); fxy = &(table.d2rhomolardxdy); break; case iSmolar: f = &(table.smolar); fx = &(table.dsmolardx); fy = &(table.dsmolardy); fxy = &(table.d2smolardxdy); break; case iHmolar: f = &(table.hmolar); fx = &(table.dhmolardx); fy = &(table.dhmolardy); fxy = &(table.d2hmolardxdy); break; case iUmolar: f = &(table.umolar); fx = &(table.dumolardx); fy = &(table.dumolardy); fxy = &(table.d2umolardxdy); break; default: throw ValueError("Invalid variable type to build_coeffs"); } for (std::size_t i = 0; i < table.Nx-1; ++i) // -1 since we have one fewer cells than nodes { for (std::size_t j = 0; j < table.Ny-1; ++j) // -1 since we have one fewer cells than nodes { if (ValidNumber((*f)[i][j]) && ValidNumber((*f)[i+1][j]) && ValidNumber((*f)[i][j+1]) && ValidNumber((*f)[i+1][j+1])){ // This will hold the scaled f values for the cell Eigen::Matrix<double, 16, 1> F; // The output values (do not require scaling F(0) = (*f)[i][j]; F(1) = (*f)[i+1][j]; F(2) = (*f)[i][j+1]; F(3) = (*f)[i+1][j+1]; // Scaling parameter // d(f)/dxhat = df/dx * dx/dxhat, where xhat = (x-x_i)/(x_{i+1}-x_i) coeffs[i][j].dx_dxhat = table.xvec[i+1]-table.xvec[i]; double dx_dxhat = coeffs[i][j].dx_dxhat; F(4) = (*fx)[i][j]*dx_dxhat; F(5) = (*fx)[i+1][j]*dx_dxhat; F(6) = (*fx)[i][j+1]*dx_dxhat; F(7) = (*fx)[i+1][j+1]*dx_dxhat; // Scaling parameter // d(f)/dyhat = df/dy * dy/dyhat, where yhat = (y-y_j)/(y_{j+1}-y_j) coeffs[i][j].dy_dyhat = table.yvec[j+1]-table.yvec[j]; double dy_dyhat = coeffs[i][j].dy_dyhat; F(8) = (*fy)[i][j]*dy_dyhat; F(9) = (*fy)[i+1][j]*dy_dyhat; F(10) = (*fy)[i][j+1]*dy_dyhat; F(11) = (*fy)[i+1][j+1]*dy_dyhat; // Cross derivatives are doubly scaled following the examples above F(12) = (*fxy)[i][j]*dy_dyhat*dx_dxhat; F(13) = (*fxy)[i+1][j]*dy_dyhat*dx_dxhat; F(14) = (*fxy)[i][j+1]*dy_dyhat*dx_dxhat; F(15) = (*fxy)[i+1][j+1]*dy_dyhat*dx_dxhat; // Calculate the alpha coefficients Eigen::MatrixXd alpha = Ainv.transpose()*F; // 16x1; Watch out for the transpose! std::vector<double> valpha = eigen_to_vec1D(alpha); coeffs[i][j].set(param, valpha); coeffs[i][j].set_valid(); valid_cell_count++; } else{ coeffs[i][j].set_invalid(); } } } double elapsed = (clock() - t1)/((double)CLOCKS_PER_SEC); if (debug){ std::cout << format("Calculated bicubic coefficients for %d good cells in %g sec.\n", valid_cell_count, elapsed); } std::size_t remap_count = 0; // Now find invalid cells and give them pointers to a neighboring cell that works for (std::size_t i = 0; i < table.Nx-1; ++i) // -1 since we have one fewer cells than nodes { for (std::size_t j = 0; j < table.Ny-1; ++j) // -1 since we have one fewer cells than nodes { // Not a valid cell if (!coeffs[i][j].valid()){ // Offsets that we are going to try in order (left, right, top, bottom, diagonals) int xoffsets[] = {-1,1,0,0,-1,1,1,-1}; int yoffsets[] = {0,0,1,-1,-1,-1,1,1}; // Length of offset std::size_t N = sizeof(xoffsets)/sizeof(xoffsets[0]); for (std::size_t k = 0; k < N; ++k){ std::size_t iplus = i + xoffsets[k]; std::size_t jplus = j + yoffsets[k]; if (0 < iplus && iplus < table.Nx-1 && 0 < jplus && jplus < table.Ny-1 && coeffs[iplus][jplus].valid()){ coeffs[i][j].set_alternate(iplus, jplus); remap_count++; if (debug){std::cout << format("Mapping %d,%d to %d,%d\n",i,j,iplus,jplus);} break; } } } } } if (debug){ std::cout << format("Remapped %d cells\n", remap_count); } } }
// Note: the phase input is currently not supported void CoolPropSolver::setState_ph(double &p, double &h, int &phase, ExternalThermodynamicState *const properties){ if (debug_level > 5) std::cout << format("setState_ph(p=%0.16e,h=%0.16e)\n",p,h); if (enable_TTSE) state->enable_TTSE_LUT(); else state->disable_TTSE_LUT(); try{ // Update the internal variables in the state instance state->update(iP,p,iH,h); if (!ValidNumber(state->rho()) || !ValidNumber(state->T())) { throw ValueError(format("p-h [%g, %g] failed for update",p,h)); } // Set the values in the output structure properties->p = p; properties->h = h; properties->d = state->rho(); properties->T = state->T(); properties->s = state->s(); if (state->TwoPhase){ properties->phase = 2; } else{ properties->phase = 1; } properties->cp = state->cp(); properties->cv = state->cv(); properties->a = state->speed_sound(); if (state->TwoPhase && state->Q() >= 0 && state->Q() <= twophase_derivsmoothing_xend) { // Use the smoothed derivatives between a quality of 0 and twophase_derivsmoothing_xend properties->ddhp = state->drhodh_constp_smoothed(twophase_derivsmoothing_xend); // [1/kPa -- > 1/Pa] properties->ddph = state->drhodp_consth_smoothed(twophase_derivsmoothing_xend); // [1/(kJ/kg) -- > 1/(J/kg)] } else if (state->TwoPhase && state->Q() >= 0 && state->Q() <= rho_smoothing_xend) { // Use the smoothed density between a quality of 0 and rho_smoothing_xend double rho_spline; double dsplinedh; double dsplinedp; state->rho_smoothed(rho_smoothing_xend, &rho_spline, &dsplinedh, &dsplinedp) ; properties->ddhp = dsplinedh; properties->ddph = dsplinedp; properties->d = rho_spline; } else { properties->ddhp = state->drhodh_constp(); properties->ddph = state->drhodp_consth(); } properties->kappa = state->isothermal_compressibility(); properties->beta = state->isobaric_expansion_coefficient(); if (calc_transport) { properties->eta = state->viscosity(); properties->lambda = state->conductivity(); //[kW/m/K --> W/m/K] properties->Pr = properties->cp*properties->eta/properties->lambda; } } catch(std::exception &e) { errorMessage((char*)e.what()); } }
bool XYZIntDialog::TransferDataFromWindow() { return ValidNumber(xbox, &xval) && ValidNumber(ybox, &yval) && ValidNumber(zbox, &zval); }