Esempio n. 1
0
double CCWashMixEffFnd::Function(double x) 
  {//x is fraction of wash to overflow
  
  //1) All solids go to underflow
  //2) Try meet user requirements for UF conc/liqFrac by adjusting wash fraction to overflow
  //3) Of the liquids reporting to the UF, we want (100%-RqdMixEff%) of liquids to retain mud liquids composition,
  //   the rest is the wash liquids.

  Qu.QSetF(Qm, som_Sol, 1.0, POut);
  Qu.QAddF(Qw, som_Sol, 1.0);
  const double WashLiqToUF = (1.0 - x)*QwLiq;
  const double RqdMudLiqToUF = WashLiqToUF*(1.0/GTZ(RqdMixEff)-1.0);
  const double RqdMudFracToUF = Min(1.0, RqdMudLiqToUF/GTZ(QmLiq));
  Qu.QAddF(Qm, som_Liq, RqdMudFracToUF);
  Qu.QAddF(Qw, som_Liq, (1.0 - x));

  Qo.QSetF(Qm, som_Liq, (1.0-RqdMudFracToUF), POut);
  Qo.QAddF(Qw, som_Liq, x);

  if (1)
    {// Correct Enthalpy...
    Qu.SetTemp(FT);
    Qo.SetTemp(FT);
    double P = POut;
    double H = Qu.totHf()+Qo.totHf();
    double dT = 0.0, H0, T0;
    for (int Hiter=0; Hiter<10; Hiter++)
      {
      if (ConvergedVV(HTot, H, 1.0e-12, 1.0e-12))
        break;
      if (dT!=0.0)
        dT = (HTot-H)*(FT-T0)/NZ(H-H0);
      else
        dT = 0.1;
      T0 = FT;
      H0 = H;
      FT += dT;
      H = Qu.totHf(som_ALL, FT, P)+Qo.totHf(som_ALL, FT, P);
      }
    Qu.SetTemp(FT);
    Qo.SetTemp(FT);
    }

  if (SA)  // Solids expressed as g/L.
    {
    double SolConc25  = Qu.PhaseConc(C_2_K(25.0), som_Sol, som_ALL);
    return SolConc25;
    }
  else    // Solids expressed as % w/w.
    {
    double solid   = Qu.QMass(som_Sol);
    double Totmass = Max(1e-6, Qu.QMass(som_ALL));
    double SolUF   = solid/Totmass;
    return SolUF;
    }
  }
Esempio n. 2
0
DuctUnit::DuctUnit(pTagObjClass pClass_, pchar TagIn, pTaggedObject pAttach, TagObjAttachment eAttach) :
  MN_Surge(pClass_, TagIn, pAttach, eAttach)
  {
  AttachIOAreas(DuctUnitIOAreaList);
  Contents.SetClosed(False);
  Contents.SetPreset(&m_Preset, &m_PresetImg);
  FlashSplit=0.1;
  SS_Lvl=0.25;

  dTInLowest=C_2_K(20.0); 
  dTInHighest=C_2_K(1000.0);
  dRqdTOutMin=C_2_K(20.0);
  dRqdTOutMax=C_2_K(1000.0);
  dRqdTOut=dNAN;
  dRqddT=dNAN;
    
  dStructMass=0.0;
  dStructTemp=C_2_K(25.0);
  dStructUA=1000.0;
  dStructCp=0.12;
  dAmbientTemp=C_2_K(25.0);
  dHeatXferCoeff=0.0;
  dHeatLossRate=0.0;
  dRqdH2OVapFrac=dNAN;

  dQmSink=0.0;
  dQmSinkMeas=dNAN;
  dQmSinkTau=2.0;
  };
Esempio n. 3
0
		virtual double RefTemp() { return C_2_K(0.0); };
Esempio n. 4
0
void FilterPress::EvalProducts()
{
	try {
		int idPressNote = 0, idWashNote = 1;
		MStreamI QFeed;
		FlwIOs.AddMixtureIn_Id(QFeed, idFeed);
		const double dFeedSolidMass = QFeed.Mass(MP_Sol);
		const double dFeedLiquidMass = QFeed.Mass(MP_Liq);

    MStreamI QWashWater;
		const bool bWashWaterConnected = (FlwIOs.getCount(idWash) > 0);
		if (bWashWaterConnected)
			FlwIOs.AddMixtureIn_Id(QWashWater, idWash);

		//MStream QUnwashedCake = QFeed; BAD idea, QUnwashedCake becomes a reference to QFeed!!!!
		MStreamI QUnwashedCake;
    QUnwashedCake = QFeed;
		QUnwashedCake.ZeroMass();

    MStream&	QFiltrate	= FlwIOs[FlwIOs.First[idFiltrate]].Stream;
    QFiltrate	= QFeed;
    MStream&	QCake		= FlwIOs[FlwIOs.First[idCake]].Stream;
    QCake		= QFeed;

		const bool bWashingsConnected = (FlwIOs.Count[idWashings] > 0);

		//First off: The filtrate & UnwashedCake:

		/*Equations Solved using Mathematica 6.0, under the constrainsts of:
		 - Conservation of mass
		 - Cake Moisture Content
		 - Filtrate Solid Concentration [Either in % or g/L]
			- When using g/L, assume solid and liquid densities don't change [The (Aq) conc's don't]
		*/
		double dSolConcConstFac, dLiqConcConstFac;
		bool bTooWet;
		switch (eFiltrateMethod) {
		case FM_SolidsToFiltrateFrac:
			dSolConcConstFac = dReqSolidsToFiltrate;
			dLiqConcConstFac = dReqSolidsToFiltrate;
			bTooWet = dFeedSolidMass / NZ(dFeedSolidMass + dFeedLiquidMass) < dReqSolidsToFiltrate;
			break;
		case FM_FiltrateConc:
			dSolConcConstFac = dReqFiltSolConc / QFeed.Density(MP_Sol, C_2_K(25));
			dLiqConcConstFac= dReqFiltSolConc / QFeed.Density(MP_Liq, C_2_K(25));
			bTooWet = dFeedSolidMass / NZ(QFeed.Volume(MP_SL, C_2_K(25))) < dReqFiltSolConc;
			break;
		}
		/*Situations where variables can be out of range:
		 - Mass comes in too wet - required loss causes all mass to be sent to filtrate
		 - Mass comes in too dry - mass is drier than required moisture frac.
		*/
		double dFiltSolidFactor, dFiltLiquidFactor, dCakeSolidFactor, dCakeLiquidFactor;
		if (bTooWet)
		{
			SetNote(idPressNote, "Input feed too wet: All feed solids sent to filtrate");
			dFiltSolidFactor = dFiltLiquidFactor = 1;
			dCakeSolidFactor = dCakeLiquidFactor = 0;
		}
		else if (dFeedLiquidMass / NZ(dFeedSolidMass + dFeedLiquidMass) < dReqCakeMoisture)
		{
			SetNote(idPressNote, "Input feed too dry: All feed liquids sent to Cake");
			dFiltSolidFactor = dFiltLiquidFactor = 0;
			dCakeSolidFactor = dCakeLiquidFactor = 1;
		}
		else
		{
			dFiltSolidFactor = (((dFeedLiquidMass * (dReqCakeMoisture - 1) + dFeedSolidMass * dReqCakeMoisture) * dLiqConcConstFac)
									/ NZ(dReqCakeMoisture * dLiqConcConstFac - (dReqCakeMoisture - 1)*(dSolConcConstFac-1))) / dFeedSolidMass;
			dFiltLiquidFactor = - (((dFeedLiquidMass * (dReqCakeMoisture - 1) + dFeedSolidMass * dReqCakeMoisture) * (dSolConcConstFac - 1))
									/ NZ(dReqCakeMoisture * dLiqConcConstFac - (dReqCakeMoisture - 1)*(dSolConcConstFac - 1))) / dFeedLiquidMass;

			dCakeSolidFactor = 1 - dFiltSolidFactor;
			dCakeLiquidFactor = 1 - dFiltLiquidFactor;
		}

		for (int i = 0; i < gs_MVDefn.Count(); i++)
			if (gs_MVDefn[i].IsSolid())
			{
				QFiltrate.M[i] = QFeed.M[i] * dFiltSolidFactor;
				QUnwashedCake.M[i] = QFeed.M[i] * dCakeSolidFactor;
			}
			else if (gs_MVDefn[i].IsLiquid())
			{
				QFiltrate.M[i] = QFeed.M[i] * dFiltLiquidFactor;
				QUnwashedCake.M[i] = QFeed.M[i] * dCakeLiquidFactor;
			}

		//Now, wash it:
		//First, add the washwater solids, and record what mass of solids we add.
		//The equations associated with this are exceedingly ugly.
		if (FlwIOs.getCount(idWash) > 0) {
			//Short variables to create fewer errors translating the equations
			double WS = QWashWater.Mass(MP_Sol);
			double WL = QWashWater.Mass(MP_Liq);
			double CS = QUnwashedCake.Mass(MP_Sol);
			double CL = QUnwashedCake.Mass(MP_Liq);
			double a, rWS, rWL, rCS, rCL;
			double m = dReqCakeMoisture;
			double w;
			switch (eWashMethod)
			{
			case WM_ConstantEfficiency:
				w = dReqWashEfficiency;
			case WM_WashRatio:
				dWashRatio = WL / NZ(CL);
				w = 1 - pow(1-dReqWashEfficiency, dWashRatio);
			}
			switch (eFiltrateMethod) {
			case FM_SolidsToFiltrateFrac:
				a = dReqSolidsToFiltrate;
				rWS = rWL = rCS = rCL = 1;
				break;
			case FM_FiltrateConc:
				a = dReqFiltSolConc;
				rWS = QWashWater.Density(MP_Sol, C_2_K(25));
				rWL = QWashWater.Density(MP_Liq, C_2_K(25));
				rCS = QUnwashedCake.Density(MP_Sol, C_2_K(25));
				rCL = QUnwashedCake.Density(MP_Liq, C_2_K(25));
				break;
			}
			/*Possible situations where variables are out of range:
			 - A: Too much wash liquid - all solids are sent out in washings ['Fix' by sending everyhing to washings. Assume we will not end up with only washing solids]
			 - B: Not enough wash liquid - required wash efficiency impossible ['Fix' by putting all wash water in cake]
			 - C: Cake comes in dry [And very dry] - wash efficiency is higher than requested even if no cake moisture is displaced. 
				[Fix by sending everything].
			 - D: Wash water has FAAR too many solids - cake moisture is lower than required. [Fix by putting everything into cake]
			 - Cake should never come in too wet.
			 */
			//CO - Cake Out. WO - Washings out.
			double dCLtoCO, dCStoCO, dWStoCO;
			
			double dTemp = (WS*rCL*rCS*rWL*(a-rWS)+(a*WL*rCL*rCS+(CS*rCL*(a-rCS)+a*CL*rCS)*rWL)*rWS)
				/ NZ(CS*(m*a*(1-w)*rCS*rWL+rCL*((1-m)*a*rWL+rCS*(m*a*w-(1-m)*rWL)))*rWS + WS*rCL*rCS*((1-m)*rWL*(a-rWS)+m*a*rWS));

			double dWLtoCO = m * (w*CS + WS) * dTemp;
			if (dWLtoCO > WL)
			{ //Case B - not enough wash liquid
				SetNote(idWashNote, "Not enough wash water: All wash water sent to cake");
				//double dTemp1 = (WS*rCL*rCS*(a-rWS)+(CS*rCL*(a-rCS)+a*CL*rCS)*rWS)
				//			/ NZ(CS*((1-m)*rCL*(a-rCS)+m*a*rCS)*rWS + WS*rCS*((1-m)*rCL*(a-rWS) + m*a*rWS));
				double dTemp1 = 1 / (CS * ((1-m) * rCL * (a-rCS) + m*a*rCS) * rWS + WS * rCS * ((1-m) * rCL * (a-rWS) + m*a*rWS));
				double dTemp2 = WS * rCL * rCS * (a-rWS) + (CS * rCL * (a-rCS) + a*(CL+WL)*rCS)*rWS;
				
				dWLtoCO = WL;
				dCLtoCO = (m*CS*CS*rCL*(a-rCS)*rWS + CS*((-(1-m)*WL*rCL*(a-rCS) + m*a*CL*rCS)*rWS+m*WS*rCL*(rCS*(a-2*rWS)+a*rWS))
							+ WS*rCS*(-(1-m)*WL*rCL*(a-rWS) + m*(WS*rCL*(a-rWS) + a*CL*rWS))) * dTemp1;
				dCStoCO = (1-m) * CS * dTemp1 * dTemp2;
				dWStoCO = (1-m) * WS * dTemp1 * dTemp2;
			}
			else
			{
				//dWLtoCO already set.
				dCLtoCO = m * (1-w) * CS * dTemp;
				dCStoCO = (1-m) * CS * dTemp;
				dWStoCO = (1-m) * WS * dTemp;
			}

			if (dCLtoCO > CL) { //Case C - not enough cake moisture [Can only happen if cake comes in with moisture content v. low.]
				dCLtoCO = CL;	//Although this results in a lower than required moisture content, well, the cake is comming in drier than required.
				SetNote(idWashNote, "Cake too dry"); }
			
			//Simple Cons of Mass:
			double dWLtoWO = WL - dWLtoCO;
			double dCLtoWO = CL - dCLtoCO;
			double dWStoWO = WS - dWStoCO;
			double dCStoWO = CS - dCStoCO;

			double dWLtoCOFrac,dCLtoCOFrac,dWStoCOFrac,dCStoCOFrac,dWLtoWOFrac,dCLtoWOFrac,dWStoWOFrac,dCStoWOFrac;
			if (dCStoCO < 0) //Case A, Too wet: Everything sent with washings
			{
				SetNote(idWashNote, "Too much liquid in WashWater. Everything sent to washings");
				dWLtoCOFrac=dCLtoCOFrac=dWStoCOFrac=dCStoCOFrac=0;
				dWLtoWOFrac=dCLtoWOFrac=dWStoWOFrac=dCStoWOFrac=1;
			}
			else if ((CL+WL)/NZ(CS+WS+CL+WL) < m)	//Case D, Too Dry: Send everything to cake.
			{
				SetNote(idWashNote, "Not enough liquid in washing stage. Everything sent to cake");
				dWLtoCOFrac=dCLtoCOFrac=dWStoCOFrac=dCStoCOFrac=1;
				dWLtoWOFrac=dCLtoWOFrac=dWStoWOFrac=dCStoWOFrac=0;
			}
			else
			{
				//Here's where we handle if we have any other zeros.
				//Also handle if a variable manages to slip by the other checks [It is possible with outlandish input parameters.]
				dWLtoCOFrac = WL > 0 ? dWLtoCO / WL : 0;
				dCLtoCOFrac = CL > 0 ? dCLtoCO / CL : 0;
				dWStoCOFrac = WS > 0 ? dWStoCO / WS : 0;
				dCStoCOFrac = CS > 0 ? dCStoCO / CS : 0;
				dWLtoWOFrac = WL > 0 ? dWLtoWO / WL : 0;
				dCLtoWOFrac = CL > 0 ? dCLtoWO / CL : 0;
				dWStoWOFrac = WS > 0 ? dWStoWO / WS : 0;
				dCStoWOFrac = CS > 0 ? dCStoWO / CS : 0;
			}

			dWashEfficiency = CL > 0 ? 1 - dCLtoCOFrac : dNAN;

		  //MStream QWashingOutput = QCake; BAD idea, QWashingOutput becomes a reference to QCake!!!!
			MStreamI QWashingOutput;
			QWashingOutput = QCake;
			QWashingOutput.ZeroMass();

			for (int i = 0; i < gs_MVDefn.Count(); i++)
				if (gs_MVDefn[i].IsSolid())
				{
					QWashingOutput.M[i] = QUnwashedCake.M[i] * dCStoWOFrac + QWashWater.M[i] * dWStoWOFrac;
					QCake.M[i] = QUnwashedCake.M[i] * dCStoCOFrac + QWashWater.M[i] * dWStoCOFrac;
				}
				else if (gs_MVDefn[i].IsLiquid())
				{
					QWashingOutput.M[i] = QUnwashedCake.M[i] * dCLtoWOFrac + QWashWater.M[i] * dWLtoWOFrac;
					QCake.M[i] = QUnwashedCake.M[i] * dCLtoCOFrac + QWashWater.M[i] * dWLtoCOFrac;
				}

			double dInputHf;
			
			MStream* pQWashingOutput;
			if (bWashingsConnected) //bWashingsConnected indicates whether OUTPUT washings are connected.
			{
				dInputHf = QUnwashedCake.totHf() + QWashWater.totHf();
				pQWashingOutput = &QWashingOutput;
			}
			else
			{
				dInputHf = QUnwashedCake.totHf() + QWashWater.totHf() + QFiltrate.totHf();
				for (int i = 0; i < gs_MVDefn.Count(); i++)
					QFiltrate.M[i] += QWashingOutput.M[i];
				pQWashingOutput = &QFiltrate;	//For thermal property managing
			}

			double dgbTi = pQWashingOutput->T;
			bool converged = false;
			for (int i = 0; i < 10 && !converged; i++)
			{
				double dbgTt = pQWashingOutput->T;

				double dOutputHf = QCake.totHf() + pQWashingOutput->totHf();

				double deltaT = -(dOutputHf - dInputHf) / NZ(pQWashingOutput->totCp() + QCake.totCp());

				pQWashingOutput->T += deltaT;
				QCake.T = pQWashingOutput->T;

				converged = abs(dInputHf - dOutputHf) < 1; //TODO: Check what sort of convergence we require.
			}

			double dbgT = pQWashingOutput->T;
			double dbgT2 = QWashingOutput.T;

			if (bWashingsConnected)
			{
				MStream& QWashings = FlwIOs[FlwIOs.First[idWashings]].Stream;
				QWashings = QWashingOutput;
			}
		}
		else //If we have no washings
		{
			if (bWashingsConnected)
			{
				MStream& QWashings = FlwIOs[FlwIOs.First[idWashings]].Stream;
				QWashings.ZeroMass();
			}
			QCake = QUnwashedCake;
		}

		//Vent:
		if (FlwIOs.Count[idVent] > 0)
		{
			MStream& QVent = FlwIOs[FlwIOs.First[idVent]].Stream;
			QVent = QCake;
			QVent.ZeroMass();
			MStreamI QWashWater;
			if (FlwIOs.Count[idWash] > 0)
				QWashWater = FlwIOs[FlwIOs.First[idWash]].Stream;
			else
				QWashWater.ZeroMass();

			for (int i = 0; i < gs_MVDefn.Count(); i++)
				if (gs_MVDefn[i].IsGas())
					QVent.M[i] = QCake.M[i] + QWashWater.M[i];
		}
		
		//Update "Actual" values.
		dCakeSolids = QCake.MassFrac(MP_Sol);
		dFiltSolids = QFiltrate.MassFrac(MP_Sol);
		dCakeSolConc = QCake.Mass(MP_Sol) / NZ(QCake.Volume(MP_All, C_2_K(25.0)));
		dFiltSolConc = QFiltrate.Mass(MP_Sol) / NZ(QFiltrate.Volume(MP_All, C_2_K(25.0)));
		if (bWashWaterConnected)
		{
			double CFeed = QFeed.SpecieConc(MP_Liq, nWashCompSpecie, C_2_K(25.0));
			double CCake = QCake.SpecieConc(MP_Liq, nWashCompSpecie, C_2_K(25.0));
			double CWash = QWashWater.SpecieConc(MP_Liq, nWashCompSpecie, C_2_K(25.0));
			dWashCompEff = (CFeed - CCake) / NZ(CFeed - CWash);
		}
		else
		{
			dWashCompEff = 0;
			dWashEfficiency = 0;
		}
	}
  catch (MMdlException &e)
    {
    Log.Message(MMsg_Error, e.Description);
    }
  catch (MFPPException &e)
    {
    e.ClearFPP();
    Log.Message(MMsg_Error, e.Description);
    }
  catch (MSysException &e)
    {
    Log.Message(MMsg_Error, e.Description);
    }
  catch (...)
    {
    Log.Message(MMsg_Error, "Some Unknown Exception occured");
    }
}
Esempio n. 5
0
/*This determines what material should leave through each outlet,
and rate of change of the contents resulting from the flow, of material, 
out of each outlet of the surge unit.
*/
void CentrifugeMB::EvalProducts(CNodeEvalIndex & NEI)
  {
  StkSpConduit Sd("Sd", chLINEID(), this);
  StkSpConduit Wd("Wd", chLINEID(), this);

  SpConduit Dummy1;
  SpConduit Dummy2;

  switch (SolveMethod())
    {
    case SM_Direct:
      {
      //RqdSolidsToFiltrate = Range(1.0e-8, RqdSolidsToFiltrate, 0.3);
      RqdSolidsToFiltrate = Range(0.0, RqdSolidsToFiltrate, 1.0);
      RqdCakeMoist  = Range(0.0, RqdCakeMoist,  0.99);
      WashEff       = Range(0.01, WashEff, 1.0);

      const int iCl = IOWithId_Self(ioidLiq);
      const int iCs = IOWithId_Self(ioidSol);
      SpConduit & Cl = *IOConduit(iCl);
      SpConduit & Cs = *IOConduit(iCs);

      const int iWw = IOWithId_Self(ioidwash);
      const int iW2 = IOWithId_Self(ioidwsh2);
      const int iFW = IOWithId_Self(ioidFW);
      const int iSW = IOWithId_Self(ioidSW);

      SpConduit & QWw = (iWw >= 1 ? *IOConduit(iWw) : Dummy1);
      SpConduit & QW2 = (iW2 >= 1 ? *IOConduit(iW2) : Dummy2);

      SigmaQInPMin(QFd, som_ALL, Id_2_Mask(ioidFd));
      const bool HasFeed = (QFd.QMass(som_ALL)>UsableMass);
      const double TtlWashSol = QWw.QMass(som_Sol) + QW2.QMass(som_Sol);

      //double CFeed = QFd.SpecieConc(QFd.Temp(), iScanEffSpecie, som_Liq);
      double CFeed = QFd.SpecieConc(QFd.Temp(), iWashEffSpecie, som_Liq);
      double CWash1 = QWw.SpecieConc(QWw.Temp(), iWashEffSpecie, som_Liq);
      double CWash2 = QW2.SpecieConc(QW2.Temp(), iWashEffSpecie, som_Liq);

      bool FeedLiqLow = false;
      double CCake1 = 0.0;
      if (fOn/* && HasFeed*/)
        {
        m_RB.EvalProducts(QFd);
        m_EHX.EvalProducts(QFd);

		    const double MSol    = QFd.QMass(som_Sol);
        const double MLiq    = QFd.QMass(som_Liq);
        const double wash1   = QWw.QMass(som_Liq);
        const double wash2   = QW2.QMass(som_Liq);
        const double TtlLiqIn = MLiq + wash1 + wash2;
        
        //will not achieve requirements if there are any solids in wash!!!
        const double MSol2Filt = MSol * RqdSolidsToFiltrate;
        const double RSol      = MSol - MSol2Filt;
        double MLiq2Cake = (RqdCakeMoist * RSol)/(1 - RqdCakeMoist); 
        FeedLiqLow = (TtlLiqIn<MLiq2Cake);
		    SetCI(1, /*fOn && */HasFeed && FeedLiqLow);
        if (FeedLiqLow)
          {//force all liquids to cake
          MLiq2Cake = TtlLiqIn;
          }
        const double TotLiq    = max(TtlLiqIn - MLiq2Cake, 1e-6);
        const double Sol2Filt  = GEZ(MLiq - MLiq2Cake) * MSol2Filt/TotLiq;

        Cs.QSetM(QFd, som_Sol, RSol, IOP_Self(iCs));
        Cs.QAddM(QWw, som_Sol, QWw.QMass(som_Sol));
        Cs.QAddM(QW2, som_Sol, QW2.QMass(som_Sol));

        Cl.QSetM(QFd, som_Liq, GEZ(MLiq - MLiq2Cake), IOP_Self(iCl));
        Cl.QAddM(QFd, som_Sol, Sol2Filt);

        //=======================================================
        if ((MSol > 1e-6) && (MLiq > 1e-6))
          {
          double Cf, Cw1, Cw2, e1, e2, w1, w2;

          w1 = min(MLiq2Cake*WashEff, wash1);
          w2 = min(MLiq2Cake*WashEff, wash2);
          e1 = w1/max(MLiq2Cake,1e-6);
          e2 = w2/max(MLiq2Cake,1e-6);

          // The liquid composition of the solids.
          Cf  = MLiq2Cake * (1.0 - e1 - e2 + e1*e2);
          Cw1 = w1 - w2*e1;
          Cw2 = w2;

          Cs.QAddM(QFd, som_Liq, Cf);
          Cs.QAddM(QWw, som_Liq, Cw1);
          CCake1 = Cs.SpecieConc(Cs.Temp(), iWashEffSpecie, som_Liq);
          Cs.QAddM(QW2, som_Liq, Cw2);

          // The filtrate and washing streams
          double Ff, Fw1, Fw2;
          Ff  = MLiq2Cake - Cf;
          Fw1 = wash1 - Cw1;
          Fw2 = wash2 - Cw2;

          if (iFW >= 1)
            {
            rSpConduit FW =*IOConduit(iFW);
            
            if (iSW >= 1)
              {//more than one washing output stream connected
              double Sw1, Sw2;
              rSpConduit SW =*IOConduit(iSW);
              Sw1 = wash1 * MSol2Filt/TotLiq;
              Sw2 = wash2 * MSol2Filt/TotLiq;

              FW.QSetM(QFd, som_Liq, w1, IOP_Self(iFW));
              FW.QAddM(QWw, som_Liq, wash1 - w1);
              FW.QAddM(QFd, som_Sol, Sw1);

              SW.QSetM(QFd, som_Liq, w2 - w1*e2, IOP_Self(iSW));
              SW.QAddM(QWw, som_Liq, w1*e2);
              SW.QAddM(QW2, som_Liq, Fw2);
              SW.QAddM(QFd, som_Sol, Sw2);
              }
            else  // everything goes to the first washings stream
              {
              FW.QSetM(QFd, som_Liq, Ff, IOP_Self(iFW));
              FW.QAddM(QWw, som_Liq, Fw1);
              FW.QAddM(QW2, som_Liq, Fw2);
              FW.QAddM(QFd, som_Sol, MSol2Filt - Sol2Filt);
              }
            }
          else  // everything goes to the filtrate
            {
            Cl.QAddM(QFd, som_Liq, Ff);
            Cl.QAddM(QWw, som_Liq, Fw1);
            Cl.QAddM(QW2, som_Liq, Fw2);
            Cl.QAddM(QFd, som_Sol, MSol2Filt - Sol2Filt);
            }
          }
        else
          {
          Cs.QAddM(QFd, som_Sol, MSol2Filt);
          Cl.QAddM(QFd, som_Liq, MLiq2Cake);
          Cl.QAddM(QWw, som_Liq, wash1);
          Cl.QAddM(QW2, som_Liq, wash2);
          }
        }
      else
        {//off
        SigmaQInPMin(Cs, som_ALL, Id_2_Mask(ioidFd));
        SigmaQInPMin(Cl, som_ALL, Id_2_Mask(ioidwash)|Id_2_Mask(ioidwsh2));
        if (iFW >= 1)
          {
          rSpConduit FW =*IOConduit(iFW);
          FW.QZero();
          }
        if (iSW >= 1)
          {
          rSpConduit SW =*IOConduit(iSW);
          SW.QZero();
          }
        }

      ActCakeLiq      = Cs.MassFrac(som_Liq);
      ActCakeSolids   = Cs.MassFrac(som_Sol);
      ActFiltSolids   = Cl.MassFrac(som_Sol);
      ActFiltSolConc  = Cl.PhaseConc(C_2_K(25.0), som_Sol, som_ALL);
      ActFiltSolConcT = Cl.PhaseConc(Cl.Temp(), som_Sol, som_ALL);
      //double Cuf = Cs.SpecieConc(Cs.Temp(), iScanEffSpecie, som_Liq);
      //double Cof = Cl.SpecieConc(Cl.Temp(), iScanEffSpecie, som_Liq);
      //ActScandrettEff = (CFeed - Cuf)/NZ(CFeed - Cof);
      const double CCake2 = Cs.SpecieConc(Cs.Temp(), iWashEffSpecie, som_Liq);
      dSpWashEff  = (CFeed - CCake1)/NZ(CFeed - CWash1);
      dSpWashEff2 = (CFeed - CCake2)/NZ(CFeed - CWash2);

      const double CMErr = fabs(ActCakeLiq - RqdCakeMoist); //CakeMoisture error
      const bool SolInWashErr = (CMErr > 1.0e-5 && TtlWashSol>1.0e-6);
		  SetCI(2, fOn && /*bTrackStatus && */HasFeed && !FeedLiqLow && !SolInWashErr && CMErr > 1.0e-5);
		  SetCI(3, fOn && /*bTrackStatus && */HasFeed && SolInWashErr);
      break;
      }
    case SM_Inline:
    case SM_Buffered:
      {
      Contents.ZeroDeriv();
      //double CFeed = Sd().SpecieConc(Sd().Temp(), iScanEffSpecie, som_Liq);
      //double CFeed = Sd().SpecieConc(Sd().Temp(), iWashEffSpecie, som_Liq);
      //double CWash1 = QWw.SpecieConc(QWw.Temp(), iWashEffSpecie, som_Liq);
      //double CWash2 = QW2.SpecieConc(QW2.Temp(), iWashEffSpecie, som_Liq);
      m_RB.EvalProducts(Sd());
      m_EHX.EvalProducts(Sd());

      double SolMass = Contents.Mass(som_Sol);
      double LiqMass = Contents.Mass(som_Liq);

      //RqdSolidsToFiltrate = Range(1.0e-8, RqdSolidsToFiltrate, 0.3);
      RqdSolidsToFiltrate  = Range(0.0, RqdSolidsToFiltrate, 1.0);
      RqdCakeMoist   = Range(0.0, RqdCakeMoist, 1.0);
      double CakeSol, LiqSol;
      LiqSol  = RqdSolidsToFiltrate / GTZ(1.0 - RqdSolidsToFiltrate);
      CakeSol = (1.0 - RqdCakeMoist) / GTZ(RqdCakeMoist);


      if (SolMass>1.0e-12 && LiqMass>1.0e-12)
        {
        SetProdMakeup(PMU_IOId | PMU_SLRatio, ioidLiq, Contents, LiqSol);
        SetProdMakeup(PMU_IOId | PMU_SLRatio, ioidSol, Contents, CakeSol);
        }
      else
        {
        // Just Operate as a Tank
        }

      SigmaQInPMin(m_QFeed, som_ALL, First64IOIds);
      EvalProducts_SurgeLevel(SolveInlineMethod(), false, ContentHgtOrd/*, &m_QFeed*/);

      if (NoProcessJoins()>=1)
        Xfer_EvalProducts(0, Joins[0].Pressure(), NULL, &m_QProdSrg, NULL, NULL, NULL);

      ActCakeLiq      = IOConduit(IOWithId_Self(ioidSol))->MassFrac(som_Liq);
      ActCakeSolids   = IOConduit(IOWithId_Self(ioidSol))->MassFrac(som_Sol);
      ActFiltSolids   = IOConduit(IOWithId_Self(ioidSol))->MassFrac(som_Sol);
      ActFiltSolConc  = IOConduit(IOWithId_Self(ioidSol))->PhaseConc(C_2_K(25.0), som_Sol, som_ALL);
      ActFiltSolConcT = IOConduit(IOWithId_Self(ioidSol))->PhaseConc(IOConduit(IOWithId_Self(ioidSol))->Temp(), som_Sol, som_ALL);
      //double Cuf = IOConduit(IOWithId_Self(ioidSol))->SpecieConc(IOConduit(IOWithId_Self(ioidSol))->Temp(), iScanEffSpecie, som_Liq);
      //double Cof = IOConduit(IOWithId_Self(ioidSol))->SpecieConc(IOConduit(IOWithId_Self(ioidSol))->Temp(), iScanEffSpecie, som_Liq);
      //ActScandrettEff = (CFeed - Cuf)/NZ(CFeed - Cof);

      break;
      }
    }
  }
Esempio n. 6
0
void CCWasher::EvalProducts(CNodeEvalIndex & NEI)
  {
  switch (SolveMethod())
    {
    case SM_Direct:
      {
      const int ioUFlw = IOWithId_Self(ioidUFlw);
      const int ioOFlw = IOWithId_Self(ioidOFlw);

      SpConduit & Qu = *IOConduit(ioUFlw);
      SpConduit & Qo = *IOConduit(ioOFlw);

      Qm.QZero();
      Qw.QZero();
      SigmaQInPMin(Qm, som_SL, Id_2_Mask(ioidMud));
      SigmaQInPMin(Qw, som_SL, Id_2_Mask(ioidWWater)|Id_2_Mask(ioidSStream));
      double CFeed = Qm.SpecieConc(Qm.Temp(), iScanEffSpecie, som_Liq);

      flag HasFlwIn = (Qm.QMass()>UsableMass || Qw.QMass()>UsableMass);
      if (fOn && HasFlwIn)
        {
        Qt.QZero();

        // Select Model Transfer 
        Qu.SelectModel(&Qm, False);
        Qo.SelectModel(&Qm, False);

        ScandrettEff      = Range(0.0, ScandrettEff, 1.0);
        MixEff            = Range(0.0, MixEff, 1.0);
        RqdUFSolidsConc25 = Range(1.0, RqdUFSolidsConc25, 5000.0);
        RqdUFSolids       = Range(0.1, RqdUFSolids, 1.0);
				Reqd_UFlowSolidsCorr = 0.0;

        double Cf = Qm.SpecieConc(Qm.Temp(), iScanEffSpecie, som_Liq);
				double Cw = Qw.SpecieConc(Qw.Temp(), iScanEffSpecie, som_Liq);
      
        m_RB.EvalProducts(Qm);
        m_EHX.EvalProducts(Qm);

        //double Qg = Qm.QMass(som_Gas);
        //Qg += Qw.QMass(som_Gas);
        //TODO CC Washer may NOT work for some reactions!

        double UFTemp = (SA ? RqdUFSolidsConc25 : RqdUFSolids);

        //double POut = AtmosPress(); //force outlet to Atmos P
        double POut = Std_P; //force outlet to Std_P
        if (iEffMethod==MEM_Scandrett)
          {
          CCWashEffFnd WEF(Cf, Cw, Qm, Qw, Qu, Qo, Qt, UFTemp, 0.0, Reqd_UFlowSolidsCorr, SA, iScanEffSpecie, POut);

          WEF.SetTarget(ScandrettEff);
          if (Valid(ByPassGuess))
            {
            WEF.SetEstimate(ByPassGuess, -1.0);
            ByPassGuess = dNAN;
            }
          flag Ok = false;
          int iRet=WEF.Start(0.0, 1.0);
          if (iRet==RF_EstimateOK) //estimate is good, solve not required
            {
            ByPassGuess = WEF.Result();
            Ok = true;
            }
          else
            {
            if (iRet==RF_BadEstimate)
              iRet = WEF.Start(0.0, 1.0); // Restart
            if (iRet==RF_OK)
              if (WEF.Solve_Brent()==RF_OK)
                {
                ByPassGuess = WEF.Result();
                Ok = true;
                }
            }
          SetCI(1, !Ok);
          }
        else //if (iEffMethod==MEM_Mixing)
          {
          CCWashMixEffFnd WF(Qm, Qw, Qu, Qo, Qt, MixEff, SA, POut);

          WF.SetTarget(UFTemp);
          if (Valid(WashByPassGuess))
            {
            WF.SetEstimate(WashByPassGuess, -1.0);
            WashByPassGuess = dNAN;
            }
          flag Ok = false;
          int iRet=WF.Start(WF.LoLimit, 1.0);
          if (iRet==RF_EstimateOK) //estimate is good, solve not required
            {
            WashByPassGuess = WF.Result();
            Ok = true;
            }
          else
            {
            if (iRet==RF_BadEstimate)
              iRet = WF.Start(WF.LoLimit, 1.0); // Restart
            if (iRet==RF_OK)
              if (WF.Solve_Brent()==RF_OK)
                {
                WashByPassGuess = WF.Result();
                Ok = true;
                }
            }
          if (SA)
            {
            SetCI(2, !Ok);
            ClrCI(3);
            }
          else
            {
            ClrCI(2);
            SetCI(3, !Ok);
            }
          }

        //put all vapours (if any) to vent (if present)
        const int iVent = IOWithId_Self(ioidVent);
        if (iVent>=0)
          {
          SpConduit & Cvent = *IOConduit(iVent);
          SigmaQInPMin(Cvent, som_Gas, Id_2_Mask(ioidMud)|Id_2_Mask(ioidWWater)|Id_2_Mask(ioidSStream));
          double Qg = Qm.QMass(som_Gas);
          Cvent.QAddM(Qm, som_Gas, Qg);
          Qg = Qw.QMass(som_Gas);
          Cvent.QAddM(Qw, som_Gas, Qg);
          }

        }
      else
        {
        Qo.QZero();
        Qu.QZero();
        const int iVent = IOWithId_Self(ioidVent);
        if (iVent>=0)
          {
          SpConduit & Cvent = *IOConduit(iVent);
          SigmaQInPMin(Cvent, som_Gas, Id_2_Mask(ioidMud)|Id_2_Mask(ioidWWater)|Id_2_Mask(ioidSStream));
          SigmaQInPMin(Qu, som_SL, Id_2_Mask(ioidMud));
          SigmaQInPMin(Qo, som_SL, Id_2_Mask(ioidWWater)|Id_2_Mask(ioidSStream));
          }
        else
          {
          SigmaQInPMin(Qu, som_ALL, Id_2_Mask(ioidMud));
          SigmaQInPMin(Qo, som_ALL, Id_2_Mask(ioidWWater)|Id_2_Mask(ioidSStream));
          }
        }
		
			UFCaustic = Qu.SpecieConc(Qu.Temp(), iScanEffSpecie, som_Liq);
		  OFCaustic = Qo.SpecieConc(Qo.Temp(), iScanEffSpecie, som_Liq);
 
			//double solid   = Qu.QMass(som_Sol);
      //double Totmass = Max(1e-6, Qu.QMass(som_ALL));
      //UFSolids = solid/Totmass;
      UFSolids = Qu.MassFrac(som_Sol);
      //OFSolids = Qo.MassFrac(som_Sol);
      ActUFSolidsConc25 = Qu.PhaseConc(C_2_K(25.0), som_Sol, som_ALL);
      //ActOFSolidsConc25 = Qo.PhaseConc(C_2_K(25.0), som_Sol, som_ALL);
      double Cuf = Qu.SpecieConc(Qu.Temp(), iScanEffSpecie, som_Liq);
      double Cof = Qo.SpecieConc(Qo.Temp(), iScanEffSpecie, som_Liq);
      ActScandrettEff = (CFeed - Cuf)/NZ(CFeed - Cof);
      break;
      }
    default:
      MN_Surge::EvalProducts(NEI);
    }
  }
Esempio n. 7
0
double CCWashEffFnd::Function(double x) 
  {
  X = x;
  // *************************** NBNB ***************************
  // These Temporary assignments are a compiler bug work around
  //dword PhS = som_Sol;
  Qt.QSetF(Qm, som_Sol, 1.0, POut);
  Qt.QAddF(Qw, som_Sol, 1.0);
  //dword PhL = som_Liq;
  Qt.QAddF(Qm, som_Liq, 1.0);
  Qt.QAddF(Qw, som_Liq, 1.0-x);
  Qt.SetTemp(FT);
  // *************************** NBNB ***************************

  const double RhoS = Range(1.0, Qt.Rho(som_Sol), 5000.0);
  const double RhoL = Qt.Rho(som_Liq);

  const double Lu   = RhoL*Su*(1.0/(U + UCorr)-1.0/RhoS);

  if (SA)
    Y = GEZ(1.0-(Lu/GTZ(Lf + (1.0 - x)*Lw)));
  else
    {
    const double solper = Range(0.1, U + UCorr, 1.0);
    const double solmas = Qt.QMass(som_Sol);
    const double LiqMas = solmas/solper - solmas;
    const double TotLiq = Max(1e-6, Qt.QMass(som_Liq));
    Y = Range(0.0, 1.0 - LiqMas/TotLiq, 1.0);
    }

  Qu.QSetF(Qt, som_Sol, 1.0, POut);
  Qu.QAddF(Qt, som_Liq, (1.0 - Y));

  Qo.QSetF(Qt, som_Liq, Y, POut);
  Qo.QAddF(Qw, som_Liq, x);

  Qu.SanityCheck();
  Qo.SanityCheck();

  if (1)
    {// Correct Enthalpy...
    Qu.SetTemp(FT);
    Qo.SetTemp(FT);
    double P = POut;
    double H = Qu.totHf()+Qo.totHf();
    double dT = 0.0, H0, T0;
    for (int Hiter=0; Hiter<10; Hiter++)
      {
      if (ConvergedVV(HTot, H, 1.0e-12, 1.0e-12))
        break;
      if (dT!=0.0)
        dT = (HTot-H)*(FT-T0)/NZ(H-H0);
      else
        dT = 0.1;
      T0 = FT;
      H0 = H;
      FT += dT;
      H = Qu.totHf(som_ALL, FT, P)+Qo.totHf(som_ALL, FT, P);
      }
    Qu.SetTemp(FT);
    Qo.SetTemp(FT);
    }

  const double Co = Qo.SpecieConc(Qo.Temp(), iScanEffSpecie, som_Liq);
  const double Cu = Qu.SpecieConc(Qu.Temp(), iScanEffSpecie, som_Liq);

  if (Converging() || TestingEstimate()) // Converging
    { 
    if (SA)  // Solids expressed as g/L.
      {
      double SolConc25  = Qu.PhaseConc(C_2_K(25.0), som_Sol, som_ALL);
      UCorr             = Range(-10.0, UCorr + U - SolConc25, 10.0);
      }
    else    // Solids expressed as % w/w.
      {
      double solid   = Qu.QMass(som_Sol);// + Qw.QMass(som_Sol);
      double Totmass = Max(1e-6, Qu.QMass(som_ALL));
      double SolUF   = solid/Totmass;
      UCorr          = Range(-0.1, UCorr + U - SolUF, 0.1);
      }
    }

  double ScandrettEff = (Cf - Cu)/NZ(Cf - Co);
  return ScandrettEff;
  }
Esempio n. 8
0
Sys13::Sys13(pTagObjClass pClass_, pchar TagIn, pTaggedObject pAttach, TagObjAttachment eAttach) :
  MdlNode(pClass_, TagIn, pAttach, eAttach),
  VH1301  ("VH1301", this, TOA_Embedded),
  VH1302  ("VH1302", this, TOA_Embedded),
  VGA1301 ("VGA1301", this, TOA_Embedded),
  VBA1301 ("VBA1301", this, TOA_Embedded),
  HBA1301 ("HBA1301", this, TOA_Embedded),
  TEGStore("TEGStore", this, TOA_Embedded),
  Q1("Q1", this, TOA_Embedded),
  Q2("Q2", this, TOA_Embedded),
  Q3("Q3", this, TOA_Embedded),
  Q4("Q4", this, TOA_Embedded),
  Q5("Q5", this, TOA_Embedded),
  Q6("Q6", this, TOA_Embedded),
  Q7("Q7", this, TOA_Embedded),
  Q8("Q8", this, TOA_Embedded),
  Q9("Q9", this, TOA_Embedded),
  Qa("Qa", this, TOA_Embedded),
  Qb("Qb", this, TOA_Embedded),
  Qc("Qc", this, TOA_Embedded)
  {
  AttachClassInfo(nc_Process, S13IOAreaList);
  AllDataHere = 1;

  VH1301.SetVolume(2.6);
  VH1302.SetVolume(2.6);
  VGA1301.SetVolume(1.0);
  VBA1301.SetVolume(26.0);
  HBA1301.SetVolume(2.0);
  TEGStore.SetVolume(2.0);

  VH1301.SetStateAction(IE_Integrate);
  VH1302.SetStateAction(IE_Integrate);
  VGA1301.SetStateAction(IE_Integrate);
  VBA1301.SetStateAction(IE_Integrate);
  HBA1301.SetStateAction(IE_Integrate);
  TEGStore.SetStateAction(IE_Integrate);

  Q1m=0.0;
  Q2m=0.0;
  Q3m=0.0;
  Q4m=0.0;
  Q5m=0.0;
  Q6m=0.0;
  Q7m=0.0;
  Q8m=0.0;
  Q9m=0.0;
  Qam=0.0;
  Qbm=0.0;
  Qcm=0.0;

  bLC13111=0;
  bLC13114=0;              bLC13117=0;
  bLC13120=0;
  bPKA1301B=0;
  bPKA1301A=0;
  bPKA1301B=0;
  bPK1302A=0;
  bPK1302B=0;
  bUHA1301A=0;
  bUHA1301B=0;
  VH1301_Lvl=0.5;
  VH1301_P=AtmosPress()+300.0;
  VH1302_Lvl=0.5;
  VH1302_P=AtmosPress()+300.0;
  VGA1301_LvlSet=0.55;
  VGA1301_Lvl=0.5;
  VGA1301_P=AtmosPress()+300.0;
  HBA1301_LvlSet=0.5;
  HBA1301_Lvl=0.5;
  HBA1301_P=AtmosPress()+300.0;
  VBA1301_Lvl=0.5;

  VGA1301_T=C_2_K(100.0);
  HBA1301_T=C_2_K(100);
  VBA1301_T=C_2_K(20.0);
  VH1301_T=C_2_K(20.0);
  VH1302_T=C_2_K(20.0);

  //VB1001_LvlSet=0.65; //  changed for external controller
  //VB1001_Lvl=0.7;     // mhm comeback - this level has to come from the glycol contacter
  //FEA13050_Qm=0.0;
  QmBoil=1.0;
  QmRich=0.0;
  QmLean=0.0;
  QmCirc=1.0;
  QmXfer=1.0;
  QmFill=1.0;
  QmSetl=10.0;

  VLVin_Posn = 1.0;


  TEGStore.ZeroMass();
  TEGStore.SetSpMass(TEG.li(), 1.0);
  TEGStore.SetTemp(C_2_K(20.0));

  };
Esempio n. 9
0
flag Sys13::ValidateData(ValidateDataBlk & VDB)
  {
  flag OK=MdlNode::ValidateData(VDB);
  VGA1301_T=(VGA1301_T < C_2_K(-20.0) || VGA1301_T > C_2_K(200.0)) ? C_2_K(20.0) : VGA1301_T;
  HBA1301_T=(HBA1301_T < C_2_K(-20.0) || HBA1301_T > C_2_K(200.0)) ? C_2_K(20.0) : HBA1301_T;
  VBA1301_T=(VBA1301_T < C_2_K(-20.0) || VBA1301_T > C_2_K(200.0)) ? C_2_K(20.0) : VBA1301_T;
  VH1301_T =(VH1301_T  < C_2_K(-20.0) || VH1301_T  > C_2_K(200.0)) ? C_2_K(20.0) : VH1301_T;
  VH1302_T =(VH1302_T  < C_2_K(-20.0) || VH1302_T  > C_2_K(200.0)) ? C_2_K(20.0) : VH1302_T;

  VGA1301.SetTemp(VGA1301_T);
  HBA1301.SetTemp(HBA1301_T);
  VBA1301.SetTemp(VBA1301_T);
  VH1301.SetTemp(VH1301_T);
  VH1302.SetTemp(VH1302_T);
  return OK;
  };