set the parameters of the single phases of the product strea

set the parameters of the single phases of the product strea

Postby CSchirmer » 07 December 2021, 07:23

I would like to set the flow rates and mole fractions, of the product streams manually separated for the vapor and liquid phase, within a CapeOpen Unit Operation. I have tried to modify the MaterialObject11Wappper.h from the c++ Mixer Splitter example as follows:
Code: Select all
bool SetSinglePhaseFromFlowTPX(CVariant& compositionL, CVariant& compositionV , double flow, double flowL, double flowV ,double fractionL, double fractionV, double T, double P, wstring& error)
    {
        HRESULT hr;
        int i;
        VARIANT empty, v, phaseList, aggState, keyComps;
        CVariant scalar;
        v.vt = empty.vt = VT_EMPTY;
        CBSTR mole(L"mole");
        CBSTR phL(L"liquid");
        CBSTR phV(L"vapor");
        //ignore aggregation states and key compounds
        VariantClear(&aggState);
        VariantClear(&keyComps);
        //check phase list
        CVariant phaseLabels; //must be destroyed when done
        phaseLabels.MakeArray(2, VT_BSTR);
        phaseLabels.SetStringAt(0, phL);
        phaseLabels.SetStringAt(1, phV);
        if (!phaseLabels.CheckArray(VT_BSTR, error))
        {
            error = L"Invalid list of possible phases from material object2: " + error;
            return false;
        }
        //set present phases on MO
        CVariant phaseStatus;
        phaseStatus.MakeArray(phaseLabels.GetCount(), VT_I4);
        for (i = 0; i < phaseLabels.GetCount(); i++) phaseStatus.SetLongAt(i, CAPE_ATEQUILIBRIUM); //we have an initial guess // CAPE_UNDEFINED
        hr = mat->SetPresentPhases(phaseLabels, phaseStatus);
        if (FAILED(hr))
        {
            error = L"Failed to set list of present phases on material object: " + error;
            return false;
        }
        scalar.MakeArray(1, VT_R8);
        //set temperature
        scalar.SetDoubleAt(0, T);
        hr = mat->SetOverallProp(CBSTR(L"temperature"), NULL, scalar);
        if (FAILED(hr))
        {
            error = L"Failed to set temperature on material object: ";
            error += CO_Error(mat, hr);
            return false;
        }
        //set pressure
        scalar.SetDoubleAt(0, P);
        hr = mat->SetOverallProp(CBSTR(L"pressure"), NULL, scalar);
        if (FAILED(hr))
        {
            error = L"Failed to set pressure on material object: ";
            error += CO_Error(mat, hr);
            return false;
        }
        // set total flow
        scalar.SetDoubleAt(0, flow);
        hr = mat->SetOverallProp(CBSTR(L"totalFlow"), mole, scalar);
        if (FAILED(hr))
        {
            error = L"Failed to set total flow on material object: ";
            error += CO_Error(mat, hr);
            return false;
        }
        scalar.SetDoubleAt(0, flowL);
        hr = mat->SetSinglePhaseProp(CBSTR(L"totalFlow"), phL, mole, scalar);
        if (FAILED(hr))
        {
            error = L"Failed to set total liquid flow on material object: ";
            error += CO_Error(mat, hr);
            return false;
        }
        scalar.SetDoubleAt(0, flowV);
        hr = mat->SetSinglePhaseProp(CBSTR(L"totalFlow"), phV, mole, scalar);
        if (FAILED(hr))
        {
            error = L"Failed to set total vapor flow on material object: ";
            error += CO_Error(mat, hr);
            return false;
        }
        //set composition
        hr = mat->SetSinglePhaseProp(CBSTR(L"fraction"), phL, mole, compositionL);
        if (FAILED(hr))
        {
            error = L"Failed to set composition of Liquid Phase on material object: ";
            error += CO_Error(mat, hr);
            return false;
        }
        hr = mat->SetSinglePhaseProp(CBSTR(L"fraction"), phV, mole, compositionV);
        if (FAILED(hr))
        {
            error = L"Failed to set composition of Vapor Phase on material object: ";
            error += CO_Error(mat, hr);
            return false;
        }
        //set fraction of phase
        /*scalar.SetDoubleAt(0, fractionL);
        hr = mat->SetSinglePhaseProp(CBSTR(L"phaseFraction"), phL, mole, scalar);
        if (FAILED(hr))
        {
            error = L"Failed to set vapor fraction on material object: ";
            error += CO_Error(mat, hr);
            return false;
        }
        scalar.SetDoubleAt(0, fractionV);
        hr = mat->SetSinglePhaseProp(CBSTR(L"phaseFraction"), phV, mole, scalar);
        if (FAILED(hr))
        {
            error = L"Failed to set vapor fraction material object: ";
            error += CO_Error(mat, hr);
            return false;
        }  */
return true;


As result no flow rate an no mole fractions are set. I get this error as result : error: calculate failed for unit AlaklineSIM1D_1: Failed to set total liquid flow on material object: invalid phase for totalFlow: can only be set for the overall phase; read-only for other phases
After removing this types of error by setting the overall totalFlow and the phaseFractions (as it is commented out in the example), I receive a new error message : error: unit AlaklineSIM1D_1 did not flash outlet stream 4

I also adjusted materialObjectWrapper and MaterialObject. I call the method in calculate() with:
Code: Select all
if (port->IsConnected())
   {
      material = port->GetMaterial();
      // set from composition, T and P and
      if (!material.SetSinglePhaseFromFlowTPX(composition_c_l, composition_c_v, m_n_dot_c_out,  m_n_dot_c_l_out , m_n_dot_c_v_out ,m_n_dot_c_l_out / m_n_dot_c_out,  m_n_dot_c_v_out / m_n_dot_c_out, T_out, p, error))
      {
         SetError(error.c_str(), L"ICapeUnit", L"Calculate");
         return false;
      }
   }


Is there a way to set the values for each phase separately?


FYI: The UO should be integrated into PRO/II. I want to set the phases manually, because an electrolyte solution is used as material and the thermodynamic data for this are scarce.
CSchirmer
 
Posts: 5
Joined: 07 July 2020, 12:15

Re: set the parameters of the single phases of the product s

Postby jasper » 07 December 2021, 10:27

It is a requirement for (stready state) CAPE-OPEN unit operation that material product ports are in phase equilibrium. Quoting the specification:

Material Objects connected to outlet ports: the Unit must have specified the conditions of each of the
material outlet ports at the end of a successful calculation. It must specify overall composition and total
flow (or component flows) and instruct the thermodynamic services to calculate the thermodynamic
phase equilibrium on the outlets by specification of two additional variables (e.g. temperature and
pressure, or pressure and enthalpy) and call of CalcEquilibrium method on the Material Object attached
to each outlet stream.


The reason for this is that whatever is downstream of the product stream does not need to know which variables have been specified by the upstream unit operation - all variables are after all consistent at phase equilibrium. In the scenario where non-equilibrium compositions and phases are allowed at the product streams, there has to be an agreement on which variables are specified (e.g. T & P).

A shortcoming of this (perhaps to be fixed in a future specification) is that you cannot copy an existing phase equilibrium (e.g. from a feed port) to a product port, without issuing a new phase equilibrium calculation.
User avatar
jasper
 
Posts: 1128
Joined: 24 October 2012, 15:33
Location: Spain


Return to Unit Operations

Who is online

Users browsing this forum: No registered users and 1 guest

cron