示例#1
0
void CPrecipitator::EvalLosses(MStream & Prod)
{
  double T = Prod.T;
  double TA = AmbientTemp();
  /// Heat Loss to internal cooling, eg Barriquands
  if (!m_bCoolerOn && iCoolMethod==COOL_Hx) {
    m_dLiquorTout = Prod.T;
    m_dLMTD = 0.0;
    m_dCoolWaterTout = CoolIn.T;
  }
  m_dIntCoolRate=0.0;
  if (m_bCoolerOn && iCoolType==COOL_INTERNAL && bCoolIn && iCoolMethod == COOL_Hx ) {
    MStreamI TubeIn;
    MStreamI TubeOut;
    MStreamI CoolOut;
    if (m_bByVolFlow) 
      m_dCoolFlow = m_dIntCoolVolFlow*Prod.Density();
    else
      m_dIntCoolVolFlow = m_dCoolFlow/Prod.Density();

    TubeIn.SetM(Prod, MP_All, m_dCoolFlow);
    TubeOut.SetF(TubeIn, MP_All, 1.0); 
    CoolOut.SetF(CoolIn, MP_All, 1.0);

    if (TubeIn.MassFlow()>0 && CoolIn.MassFlow()>0) {

	m_dUA=m_dCoolArea*m_dCoolHTC;
	CCoolerFn Fn(m_dUA, TubeIn, CoolIn, TubeOut, CoolOut);

	double TubeOutT;
	double MxTbOutT=TubeIn.T;// No Transfer
	double MnTbOutT=CoolIn.T+0.001;
 	double qShell=-CoolIn.totHz()+CoolOut.totHz(MP_All, TubeIn.T);
 	double qTube= -TubeIn.totHz(MP_All, CoolIn.T)+TubeIn.totHz();
      
	if (qShell<qTube) // Limited By Shell - Tube TOut Limited
	  MnTbOutT=MxTbOutT - (qShell)/GTZ(qTube)*(MxTbOutT-MnTbOutT);

      switch (Fn.FindRoot(0, MnTbOutT, MxTbOutT)) {
      case RF_OK:       TubeOutT = Fn.Result();   break;
      case RF_LoLimit:  TubeOutT = MnTbOutT;      break;
      case RF_HiLimit:  TubeOutT = MxTbOutT;      break;
      default: 
	Log.Message(MMsg_Error, "TubeOutT not found - RootFinder:%s", Fn.ResultString(Fn.Error())); 
	TubeOutT=Fn.Result();
	break;
      }
      TubeOut.T = TubeOutT;
      m_dIntCoolRate = TubeIn.totHz() - TubeOut.totHz();
      m_dCoolWaterTout = CoolOut.T;
      m_dCoolWaterTin = CoolIn.T;
      m_dCoolWaterFlow = CoolIn.Mass();
      m_dCoolWaterFlowVol = CoolIn.Volume();
      m_dLiquorTout = TubeOut.T;
      m_dLMTD=fabs(LMTD(TubeIn.T, TubeOut.T, CoolIn.T, CoolOut.T));
    }



  }
    
  if (iCoolType==COOL_INTERNAL && iCoolMethod == COOL_dQ ) {
    m_dIntCoolRate = m_dCooldQ;
  }
  






  switch (iCoolType) {
  case COOL_NONE:
    m_dCoolRate = 0;
    break;
  case COOL_EXTERNAL:
    m_dCoolRate = m_dExtCoolRate;    // kW
    break;
  case COOL_INTERNAL:
  /// Heat Loss to internal cooling, eg draft tube coolers
    m_dCoolRate = m_dIntCoolRate;
    break;
  }
  

  /// Evaporation Rate
  switch (iEvapMethod) {
  case EVAP_dT:
    m_dEvapRate = m_dEvapRateK*(T-TA);       // kg/s
    x[3] = m_dEvapRate;
    break;
  case EVAP_FIXED:
    x[3] = m_dEvapRate;
    break;
  case EVAP_NONE:
    x[3] = 0;
    m_dEvapRate = 0.0;
    
  }  

  /// Evaporative Heat Loss ... need to fix this up using stream enthalpies
  m_dEvapThermalLoss = 2300*m_dEvapRate;   // kW...


  /// Heat Loss to ambient cooling
  m_dEnvironmentLoss = 0.0;
  switch (iThermalLossMethod) {
  case THL_Ambient:
    m_dEnvironmentLoss = (T-TA)*dThermalLossAmbient;  //kW
    break;
  case THL_FixedHeatFlow:
    m_dEnvironmentLoss = dThermalLossRqd;
    break;
  }
  
  m_dTotThermalLoss = m_dEnvironmentLoss + m_dEvapThermalLoss + m_dCoolRate;
  
}
示例#2
0
void BatchPrecip::EvalProducts()
  {
  #if ForceOptimizeOff
  static Cnt = 0;
  if (stricmp(getTag(), "SpeciauxUE")==0)
    {
    Cnt++;//place breakpoint here to stop for specified model
    }
  #endif
  if (!IsSolveDirect)//(!IsProbal)
    return;
  bool Err = true;
  try
    {
    MStreamI Slurry;
    MStreamI Liquor;
    FlwIOs.AddMixtureIn_Id(Slurry, idSlurry); //sum all input slurry streams
    m_bHasLiquor = (FlwIOs.First[idLiquor]>=0); //test if liquor stream connected
    if (m_bHasLiquor)
      {
      FlwIOs.AddMixtureIn_Id(Liquor, idLiquor); //sum all input liquor streams
      //double LiquorSolids = Liquor.Mass();
      }
    MStream & Prod = FlwIOs[FlwIOs.First[idDrawOff]].Stream; //get a reference to the single output stream
    
    Prod = Slurry; //set output stream = input stream (including PSD data, etc)
    m_dThermalLoss = 0.0;
    m_dYield = 0.0;
    m_dTempIn = Slurry.T;
    MIBayer & SlurryB = *Slurry.FindIF<MIBayer>(); //get access to bayer properties interface for stream
    if (!IsNothing(SlurryB))
      {
      m_dACIn = SlurryB.AtoC();
      m_dSolidConcIn = SlurryB.SolidsConc(C2K(25.0));
      }
    else
      {
      m_dACIn = 0.0;
      m_dSolidConcIn = 0.0;
      }
    
    if (m_bOn && Slurry.Mass()>UsableMass)
      {
      MIBayer & ProdB = *Prod.FindIF<MIBayer>();
      Log.SetCondition(IsNothing(ProdB), 1, MMsg_Warning, "Bad Slurry Stream - Not Bayer Model"); //expect stream to have bayer properties
      
      if (!IsNothing(SlurryB) && !IsNothing(ProdB))
        {
		// ---   --- Thermal Losses. ------------
		// !! this should be done COMBINED with FLAHSING/evaporation as the Caustic concentration should increase
		Slurry.SetTP(Slurry.T -m_dFillingTempDrop, Slurry.P);
		Liquor.SetTP(Liquor.T -m_dFillingTempDrop, Liquor.P);

        double SlurryH0 = Slurry.totHf(MP_All, Slurry.T, Slurry.P);
		double LiquorH0 = (m_bHasLiquor ? Liquor.totHf(MP_All, Liquor.T, Liquor.P) : 0.0);
 
       //Prod.SetTemp(Prod.Temp()-m_dTempDrop);
	
	    RunSteady(Slurry, Liquor, Prod);
        
        m_dThermalLoss = (SlurryH0+LiquorH0)-Prod.totHf(MP_All, Prod.T, Prod.P);
        
        m_dACOut = ProdB.AtoC();
        m_dSolidConcOut = ProdB.SolidsConc(C2K(25.0));
        //m_dResTime = TankVol/GTZ(Prod.Volume(som_SL));
        double Cout = ProdB.CausticConc(Prod.T);
        m_dYield = Cout*(m_dACIn-m_dACOut);
        }
		  if (sm_bCompletePopulation)
			  m_QProd = Prod;//copy the content of the stream in the equipement only if STILL in Pop mode
      }
    else
      {
      if (m_bHasLiquor)
        {      
        Prod.AddF(Liquor, MP_All, 1.0);
        }
      MIBayer & ProdB = *Prod.FindIF<MIBayer>();
      if (!IsNothing(ProdB))
        {
        m_dACOut = ProdB.AtoC();
        m_dSolidConcOut = ProdB.SolidsConc(C2K(25.0));
        }
      else
        {
        m_dACOut = 0.0;
        m_dSolidConcOut = 0.0;
        }
      }
    m_dTempOut = Prod.T;
    Err = false;
    }
  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");
    }

  if (Err)
    {//Something is wrong!!!  Bug needs fixing!!! 
    //So lets set product=feed....
    MStreamI Feed;
    MStream & Prod = FlwIOs[FlwIOs.First[idDrawOff]].Stream; //get a reference to the single output stream

    FlwIOs.AddMixtureIn_Id(Feed, idSlurry); //sum all input slurry streams
    Prod = Feed;
    if (FlwIOs.First[idLiquor]>=0)
      {
      MStreamI Liquor;
      FlwIOs.AddMixtureIn_Id(Liquor, idLiquor); //sum all input liquor streams
      Prod.AddF(Liquor, MP_All, 1.0);
      }
    CString ProblemModel;
    ProblemModel = getTag();
    //SetStopRequired("Phone Denis!");
    }
  Log.SetCondition(Err, 5, MMsg_Error, "Error needs fixing!!!");
  }
示例#3
0
void FlotationCell::EvalProducts()
{
	try
	{
		dPrimaryRecovery = dReqPrimaryRecovery;
		dPrimaryGrade = dReqPrimaryGrade;
		for (unsigned int i = 0; i < vSecondaryRecoveries.size(); i++)
			vSecondaryRecoveries.at(i) = vReqSecondaryRecoveries.at(i);

		//sum all input streams into a working copy
		MStreamI QI;
		FlwIOs.AddMixtureIn_Id(QI, idFeed);
		MStreamI QAir;
		FlwIOs.AddMixtureIn_Id(QAir, idAir);
		bool bAirOn = FlwIOs.Count[idAir] > 0;

		//get handles to output streams...
		MStream & QOT = FlwIOs[FlwIOs.First[idTail]].Stream;
		MStream & QOC = FlwIOs[FlwIOs.First[idConc]].Stream;
		MStream & QOV = FlwIOs[FlwIOs.First[idVent]].Stream;

		QOT = QI;
		QOT.ZeroMass();
		QOC = QI;
		QOC.ZeroMass();

		if (!m_bOn)
		{
			QOT = QI;
			QOV = QAir;
			dPrimaryRecovery = dPrimaryGrade = 0;
			for (vector<double>::iterator it = vSecondaryRecoveries.begin(); it != vSecondaryRecoveries.end(); it++)
				*it = 0.0;
			return;
		}
		if (QI.Mass(MP_Sol) > QI.Mass(MP_Liq))
			Log.SetCondition(true, LC_BadInput, MMsg_Warning, "Input stream contains more solid than liquid.");

		if (bAirOn && (QAir.Mass(MP_Sol) > UsableMass || QAir.Mass(MP_Liq) > UsableMass))
			Log.SetCondition(true, LC_BadAir, MMsg_Warning, "Air stream contains liquids or solids");
		if (bAirOn && QAir.Volume(MP_Gas) < 2 * QI.Volume(MP_Sol))
			Log.SetCondition(true, LC_LittleAir, MMsg_Warning, "Air stream contains very little gas");

		QI.AddF(QAir, MP_All, 1);

		//do the work...
		const int NumSpecies = gs_MVDefn.Count();

		//Primaries:
		double dPrimaryMassConc = 0.0;
		double dPrimaryElementConc = 0.0;
		for (unsigned int i = 0; i < vPrimaryIndices.size(); i++)
		{
			double temp = QI.M[vPrimaryIndices.at(i)];
			dPrimaryMassConc += temp * dReqPrimaryRecovery;
			if (eSpecType == FTST_ByElement)
				dPrimaryElementConc += temp * dPrimaryRecovery * ElementMassFrac(vPrimaryIndices.at(i), nPrimary1);
			else
				dPrimaryElementConc += temp * dPrimaryRecovery;

			QOT.M[vPrimaryIndices.at(i)] = temp * (1 - dReqPrimaryRecovery);
			QOC.M[vPrimaryIndices.at(i)] = temp * dReqPrimaryRecovery;
		}

		if (dPrimaryElementConc == 0)
		{
			dPrimaryRecovery = dNAN;
			Log.SetCondition(true, LC_NoPrimaries, MMsg_Warning, "No primary compounds found in feed.");
		}

		//Secondaries:
		double dSecondaryMassConc = 0.0;
		for (unsigned int i = 0; i < vSecondaryIndices.size(); i++)
		{
			double temp = QI.M[vSecondaryIndices.at(i)];
			dSecondaryMassConc += temp * vReqSecondaryRecoveries.at(i);
			QOT.M[vSecondaryIndices.at(i)] = temp * (1 - vReqSecondaryRecoveries.at(i));
			QOC.M[vSecondaryIndices.at(i)] = temp * vReqSecondaryRecoveries.at(i);
			if (eSpecType == FTST_ByElement)
				dPrimaryElementConc += temp * vReqSecondaryRecoveries.at(i) * ElementMassFrac(vSecondaryIndices.at(i), nPrimary1);
		}

		//Those not included in either primaries or secondaries.
		double dPrimaryElementInGangue = 0;
		double dOtherMassIn = 0.0;
		for (unsigned int i = 0; i < vOtherIndices.size(); i++)
		{
			dOtherMassIn += QI.M[vOtherIndices.at(i)];
			if (eSpecType == FTST_ByElement)
				dPrimaryElementInGangue += QI.M[vOtherIndices.at(i)] * ElementMassFrac(vOtherIndices.at(i), nPrimary1);
		}
		double dPrimaryGangueFrac = dPrimaryElementInGangue / NZ(dOtherMassIn);

		double dReqOtherMassOut = (dPrimaryElementConc - dReqPrimaryGrade * (dPrimaryMassConc + dSecondaryMassConc)) / NZ(dReqPrimaryGrade - dPrimaryGangueFrac);
		if (dReqOtherMassOut < 0) //If this is the case, we will put in no more impurities.
		{
			if (dPrimaryElementConc / QOC.Mass(MP_Sol) < dReqPrimaryGrade)
			{
				Log.SetCondition(true, LC_NoGrade, MMsg_Warning, "Secondary products prevent required primary grade");
				dReqOtherMassOut = 0;
			}
			else
			{
				Log.SetCondition(true, LC_NoGrade, MMsg_Warning, "Grade of gangue to concentrate higher than required grade");
				if (dPrimaryElementConc / QOC.Mass(MP_Sol) > dPrimaryGangueFrac) //We will get as close as possible...
					dReqOtherMassOut = dOtherMassIn;
			}
		}
		if (dReqOtherMassOut > dOtherMassIn)
		{
			Log.SetCondition(true, LC_NoGrade, MMsg_Warning, "Not enough unspecified input mass to achieve required primary grade");
			dReqOtherMassOut = dOtherMassIn;
		}
		for (unsigned int i = 0; i < vOtherIndices.size(); i++)
		{
			QOC.M[vOtherIndices.at(i)] = QI.M[vOtherIndices.at(i)] * dReqOtherMassOut / NZ(dOtherMassIn);
			QOT.M[vOtherIndices.at(i)] = QI.M[vOtherIndices.at(i)] * (1 - dReqOtherMassOut / NZ(dOtherMassIn));
		}
		dPrimaryElementConc += dReqOtherMassOut * dPrimaryGangueFrac;

		//Finally: We deal with non-solid species:
		/*for (int i = 0; i < gs_MVDefn.Count(); i++)
		{
			if (gs_MVDefn[i].IsSolid())
				continue;
			QOC.M[i] = QI.M[i] * dReqWaterFrac;
			QOT.M[i] = QI.M[i] * (1 - dReqWaterFrac);
		}*/
		QOC.AddM(QI, MP_Liq, QI.Mass(MP_Liq) * dReqWaterFrac);
		QOT.AddM(QI, MP_Liq, QI.Mass(MP_Liq) * (1 - dReqWaterFrac));
		if (FlwIOs.Count[idVent] > 0)
		{
			QOV = QI;
			QOV.ZeroMass();
			QOV.AddM(QI, MP_Gas, QI.Mass(MP_Gas));
		}
		else
		{
			QOC.AddM(QI, MP_Gas, QI.Mass(MP_Gas));
			if (FlwIOs.Count[idAir] > 0)
				Log.SetCondition(true, LC_Vent, MMsg_Warning, "Stream connected to air, but no stream connected to vent.");
		}

		if (QOC.Mass(MP_Sol) > 0)
			dPrimaryGrade = dPrimaryElementConc / NZ(QOC.Mass(MP_Sol));
		else
			dPrimaryGrade = dNAN;
		dSfConcentrate = QOC.MassFrac(MP_Sol);
		dSfTailings = QOT.MassFrac(MP_Sol);
  }
  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");
    }
  }