void CapeOpenCalculator::doCalcOverall()
{
    // Collect all props to calc.

    CVariant propNames;
    propNames.MakeArray(COPropsOverall::Count, VT_BSTR);
    for (size_t i = 0; i < COPropsOverall::Count; i++)
    {
        propNames.SetStringAt(i, COPropsOverall::At[i]);
    }

    // Only overall phase.
    CVariant phaseNames;
    phaseNames.MakeArray(1, VT_BSTR);
    phaseNames.SetStringAt(0, COPhasesOverall::OVERALL);

    // The calculation.
    _socket->CalcProps(propNames, phaseNames);
}
void CapeOpenCalculator::doCalcPhases(const size_t* phaseIds, size_t nPhases)
{
    // Collect all props to calc.
    CVariant propNames;
    propNames.MakeArray(COProps1Ph::Count, VT_BSTR);
    for (size_t i = 0; i < COProps1Ph::Count; i++)
    {
        propNames.SetStringAt(i, COProps1Ph::At[i]);
    }

    // Collect all phases to calc.
    CVariant phaseNames;
    phaseNames.MakeArray(nPhases, VT_BSTR);
    for (size_t i = 0; i < nPhases; i++)
    {
        phaseNames.SetStringAt(i, COPhases1Ph::At[phaseIds[i]]);
    }

    // The calculation.
    _socket->CalcProps(propNames, phaseNames);
}
CapeOpenCalculator::CapeOpenCalculator(const MaterialCalculatorSetup* setupInfo)
                  : BaseCalculator(setupInfo)
{
    // Get the property package name from the library name
    string packageName = _libraryName.substr(_libraryName.find(".")+1);

    if (packageName.find("StanMix")     != string::npos ||
        packageName.find("PCP-SAFT")    != string::npos ||
        packageName.find("TPSI")        != string::npos ||
        packageName.find("vThermo")     != string::npos ||
        packageName.find("GasMix")      != string::npos ||
        packageName.find("IF97")        != string::npos ||
        packageName.find("RefProp")     != string::npos)
    {
        warningMessage("CapeOpenCalculator", "Calculation of properties under "
                       "specific phases is not supported by this property "
                       "package. The returned values will be an average over "
                       "the present phases.\n");
    }

    // Get the property package by its name
    LPDISPATCH pack;
    HRESULT hr = ppm->getPropertyPackage(packageName, &pack);
    if (FAILED(hr))
    {
        errorMessage("CapeOpenCalculator", "Unable to load the specified "
                     "property package.\nCAPE-OPEN error:\n\t%s",
                     COUtilities::GetCOErrorAsString(pack, hr).c_str());
        return;
    }

    // The socket handles the property package from here.
    _socket = new CapeOpenSocket_1_0(pack);
    pack->Release();

    // Set the substance on the material object
    CVariant compIds;
    compIds.MakeArray(_numCompounds, VT_BSTR);
    compIds.SetStringAt(0, _bstr_t(setupInfo->compounds));

    for(int i = 0; i < _numCompounds; ++i)
    {
        compIds.SetStringAt(i, _bstr_t(_compounds[i].c_str()));
    }

    // set component ids of material object
    _socket->GetMaterialObject()->setComponentIds(compIds.Value());

    // Get the phase ids in order to determine which constants should be available
    CVariant phaseNames;
    //phaseNames.MakeArray(COPhases1Ph::Count, VT_R8);
    _socket->GetSupportedPhases(phaseNames);

    _socket->GetMaterialObject()->setVaporPhasePossible(false);
    _socket->GetMaterialObject()->setLiquidPhasePossible(false);
    _socket->GetMaterialObject()->setSolidPhasePossible(false);

    std::wstring error;
    if (phaseNames.CheckArray(VT_BSTR, error))
    {
        // Add the packages to the list.
        for (int i = 0; i < phaseNames.GetCount(); ++i)
        {
            BSTR phaseName = phaseNames.GetStringAt(i);

            if(lstrcmpi(phaseName, COPhases1Ph::VAPOR) == 0)
                _socket->GetMaterialObject()->setVaporPhasePossible(true);
            if(lstrcmpi(phaseName, COPhases1Ph::LIQUID) == 0)
                _socket->GetMaterialObject()->setLiquidPhasePossible(true);
            if(lstrcmpi(phaseName, COPhases1Ph::SOLID) == 0)
                _socket->GetMaterialObject()->setSolidPhasePossible(true);
        }
    }

    // set the fluid constants
    this->setSubstanceConstants();
}
void CapeOpenCalculator::setSubstanceConstants()
{
    // Let the property package calc the constant props
    CVariant props;

    if(_socket->GetMaterialObject()->getLiquidPhasePossible())
        props.MakeArray(COPropsConst::Count, VT_BSTR);
    else
        props.MakeArray(1, VT_BSTR);

    for (int i = 0; i < COPropsConst::Count; i++)
    {
        if(wcscmp(COPropsConst::At[i], COPropsConst::TCRIT) == 0 || wcscmp(COPropsConst::At[i], COPropsConst::PCRIT) == 0)
        {
            if(_socket->GetMaterialObject()->getLiquidPhasePossible())
            {
                props.SetStringAt(i, COPropsConst::At[i]);
            }
            else
            {
                warningMessage("CapeOpenCalculator", "Fluid constant \"%S\" is unavailable for %s.",
                       COPropsConst::At[i], _libraryName.c_str());
            }
        }
        else
        {
            props.SetStringAt(i, COPropsConst::At[i]);
        }
    }

    CVariant results;
    results.MakeArray(COPropsConst::Count * _numCompounds, VT_VARIANT);

    _socket->GetConstants(props, results);

    // Get the results
    for(int i = 0; i < _numCompounds; ++i)
    {
        FluidConstants fc;
        fc.MM = V_R8(&results.GetVariantAt(COPropsConst::MMOL_ID * _numCompounds + i)); // result is expected in kg/mol (SI)!

        if(_socket->GetMaterialObject()->getLiquidPhasePossible())
        {
            fc.Tc = V_R8(&results.GetVariantAt(COPropsConst::TCRIT_ID * _numCompounds + i));
            fc.pc = V_R8(&results.GetVariantAt(COPropsConst::PCRIT_ID * _numCompounds + i));
        }
        this->_fluidConstants.push_back(fc);
    }

    // set molar mass of material object (mixtures: temporarily set to molar mass of first compound, total/average is calculated in setSubstanceProperties())
    _socket->GetMaterialObject()->setMM(_fluidConstants[0].MM);

    // TODO: Get the other constants using a flash
    /*
    this->doFlash(this->_fluidConstants.pc, this->_fluidConstants.Tc,
                  COPropsOverall::PRESSURE, COPropsOverall::TEMPERATURE,
                  COFlashTypes::TP);
    this->doCalcOverall();
    this->getPropOverall(COPropsOverall::DENSITY, this->_fluidConstants.dc);
    this->getPropOverall(COPropsOverall::ENTHALPY, this->_fluidConstants.hc);
    this->getPropOverall(COPropsOverall::ENTROPY, this->_fluidConstants.sc);
    */
}