Example #1
0
/** 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;
	}	
}
Example #4
0
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;
}
Example #5
0
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));
}
Example #6
0
/**
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;
}
Example #9
0
// 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);
}
Example #10
0
/**
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;
}
Example #11
0
// 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]);
}
Example #13
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]")));
Example #14
0
/**

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;
}
Example #15
0
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);
        }
    }
}
Example #16
0
// 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());
	}
}
Example #17
0
bool XYZIntDialog::TransferDataFromWindow()
{
    return ValidNumber(xbox, &xval) &&
           ValidNumber(ybox, &yval) &&
           ValidNumber(zbox, &zval);
}