Пример #1
0
  bool BatchPrecip::PrecipBatchSS(double dTime, MVector & Prod, double CurLevel)
  {
  MIBayer & ProdB   = *Prod.GetIF<MIBayer>();
  MIPSD & ProdSz    = *Prod.FindIF<MIPSD>();
  MISSA & ProdSSA   = *Prod.FindIF<MISSA>();
  double TProd = Prod.getT();
  double gpl1 = ProdB.SolidsConc(TProd);
  double ProdVolFlow = Prod.Volume(MP_All);
  double SolidsInitial  = Prod.Mass(MP_Sol);

  double Sx;
  if (!sm_bCompletePopulation && sm_bUsePrevPSD)
    {
    MISSA & PrevSSA=*m_QProd.FindIF<MISSA>();// this is the SSA of the last Popul run to use in "NO POpul mode"
    if (IsNothing(PrevSSA))
      {
	   m_bPrevPSDUsed = 0;
      Sx=ProdSSA.SpecificSurfaceAreaMass(); //m^2/g//PROBLEM!!! Prev does not have SSA, use feed
      }
    else
      {
	  m_bPrevPSDUsed = 1;
      Sx=PrevSSA.SpecificSurfaceAreaMass(); //m^2/g
      }
    }
  else
    {
	m_bPrevPSDUsed = 0;
    Sx = m_dInTankSSA ; // the SSA value manually entered by the user in m^2/g
    }
  Sx=Range(0.020, Sx, 0.085);
 
  //=== mass balance ===
  double T0 = Prod.T;
  double Ain2 = ProdB.AluminaConc(C2K(25.0));
  double Cin2 = ProdB.CausticConc(C2K(25.0));
  double ASat2 = ProdB.AluminaConcSat(T0);
  double SSat2 = (Ain2-ASat2)/GTZ(Cin2);
  double NoPerSec2 = ProdSSA.PartNumPerSec();
  double enthIn = Prod.totCp(MP_All) * K2C(T0); // Enthalpie IN

  double PrecipRate1 = get_PrecipRate(Prod, Sx);
  gpl1 =  gpl1 - PrecipRate1 * dTime*156/102 ;

  bool CErr;
  const double Na2OFac = get_Na2OFactor(Prod);

  PerformAluminaSolubility(Prod, dNAN, dNAN, gpl1, 0, Na2OFac, SSat2, CErr);

  double T1 = Prod.T;
 
  double SolidsVariation =  (Prod.Mass(MP_Sol) - SolidsInitial); //* 0.97 ;// 0.97 is to compensate for the HYPROD error
  HeatBalance(Prod, SolidsVariation, enthIn, dTime, CurLevel);  // Éliminé pour vérifier la temp ?
  
  return true;
  }
Пример #2
0
bool BatchPrecip::BatchCycle(MVector & Slurry, MVector & Liquor, MVector & Prod)
  {
  double dt;
  MIBayer & SlurryB = *Slurry.GetIF<MIBayer>();
  MIBayer & ProdB   = *Prod.GetIF<MIBayer>();
  MIPSD & SlurrySz  = *Slurry.FindIF<MIPSD>();
  MIPSD & ProdSz    = *Prod.FindIF<MIPSD>();
  MISSA & SlurrySSA = *Slurry.FindIF<MISSA>();
  MISSA & ProdSSA   = *Prod.FindIF<MISSA>();
  Log.SetCondition(IsNothing(SlurrySz) || IsNothing(ProdSz), 2, MMsg_Error, "Bad Slurry Stream - No Size Distribution");
  Log.SetCondition(IsNothing(SlurrySSA) || IsNothing(ProdSSA), 3, MMsg_Error, "Bad Slurry Stream - No SSA Data");

  m_dCirculationTime = Max(1.0, m_dCirculationTime);
  m_dSeedingTime     = Max(1.0, m_dSeedingTime);
  m_dDrawOffTime     = Max(1.0, m_dDrawOffTime);
  m_dFillingTime     = Max(1.0, m_dFillingTime);
  m_dFillingTempDrop = Max(0.0, m_dFillingTempDrop);

  if (!IsNothing(ProdSz) && !IsNothing(ProdSSA))
    {
    if (!InitSizeData(Prod))
      return false;

    InitAgloData(m_eAgloModel, m_dAgloParam[int(m_eAgloModel)]);

    double *ProdPSD=ProdSz.getFracVector(0); //array of PSD data

    //Determine adjusted filtrate and slurry feed for "single" tank
    double SlurryTtlFlow = Slurry.Volume();
    if (SlurryTtlFlow<1.0e-6)
      return true;
    double LiquorTtlFlow = (m_bHasLiquor ? Liquor.Volume() : 0.0);
    if (m_bHasLiquor && LiquorTtlFlow<1.0e-6)
      return true; //todo error message
    double CombinedFlows = SlurryTtlFlow + LiquorTtlFlow;
    const double SlurryTtlMassFlow = Slurry.Mass();
    const double LiquorTtlMassFlow = (m_bHasLiquor ? Liquor.Mass() : 0.0);

    bool ContSeeding = !m_bHasLiquor;
    double FractionFiltrate = 0.0;
    double SeedFlow = 0.0;
    double FillFlow = 0.0;
    if (ContSeeding)
      {
      SeedFlow = (m_dVolume*m_dLevel) / (m_dFillingTime+m_dSeedingTime);// !! in that CASE filling means the PL&Seed filling time
      Slurry.AdjustMassTo(MP_All, SlurryTtlMassFlow*SeedFlow/SlurryTtlFlow);
      }
    else
      {
      FractionFiltrate = LiquorTtlFlow / (LiquorTtlFlow+SlurryTtlFlow);
      FillFlow = (m_dVolume*m_dLevel) * FractionFiltrate / m_dFillingTime;
      SeedFlow = (m_dVolume*m_dLevel) * (1.0-FractionFiltrate) / m_dSeedingTime;
      Liquor.AdjustMassTo(MP_All, LiquorTtlMassFlow*FillFlow/LiquorTtlFlow);
      Slurry.AdjustMassTo(MP_All, SlurryTtlMassFlow*SeedFlow/SlurryTtlFlow);
      //Liquor.SetF(Liquor, MP_All, FillFlow/LiquorTtlFlow);
      }

    /*if (m_dNbTankAvailable<=0.0)
      {
      Nb = (m_dFilltime + m_dSeedingTime + Recirc_t +DrawOff_t) * ( CombinedFlows) / (m_dVolume*level);
      }*/
    //todo: No Of Tanks???

    double iLevel;
    if (ContSeeding)
      {
      iLevel = 0.2;
      const double TimeSoFar = iLevel*(m_dVolume*m_dLevel) / Slurry.Volume();
      const double d = Slurry.Mass()* TimeSoFar ;//kg
      Prod.SetM(Slurry, MP_All, d);
      //const double d = iLevel*(m_dVolume*m_dLevel) / Slurry.Volume();
      //Prod.SetF(Slurry, MP_All, d);
      // les valeurs dans PrecipResult ne sont plus des debits mais des volumes et des masses;
      }
    else
      {
      iLevel = FractionFiltrate;
      const double d = Liquor.Mass()*m_dFillingTime;//kg
      Prod.SetM(Liquor, MP_All, d);
      // les valeurs dans PrecipResult ne sont plus des debits mais des volumes et des masses;
      // todo !!!!! reduire la temperature du filtrat et Flash
      }

    double ProdSSurf;
    MassFrac2HyprodDist(SizeClass, ProdPSD, ProdHyPsd, NIntervals, ProdSSurf); //gets PSD for 1 gpl

    double target = m_dLevel;

    //add seed until specified level (filling tank)
    while (iLevel < target)
      {
      double dt = 36.0; //seconds
      if ( (iLevel + Slurry.Volume()*dt/(m_dVolume*m_dLevel)) > target )
        dt = fabs( (target-iLevel) * (m_dVolume*m_dLevel) / Slurry.Volume());
      if (dt>0.0000001)
        {
        iLevel += (Slurry.Volume()*dt/(m_dVolume*m_dLevel));

        //MixBatch...
        HyprodDist2MassFrac(SizeClass, ProdHyPsd, ProdPSD, NIntervals);
        Prod.AddM(Slurry, MP_All, Slurry.Mass()*dt);
        MassFrac2HyprodDist(SizeClass, ProdPSD, ProdHyPsd, NIntervals, ProdSSurf); //gets PSD for 1 gpl

        //precip reaction...
        if (ProdB.SolidsConc(C2K(25.0))>5.0) // need a minimum solid conc. to precipitate
		   if (sm_bCompletePopulation)
				{
				if (!PrecipBatch(dt, Prod, iLevel,m_bAgglomONwhileFilling))// with population balance
					return false;
				}
			else
				{
				if (!PrecipBatchSS(dt, Prod, iLevel))// with SSA
					return false;
				}
        //application.processMessages;
        //if flowsheet.UserCancel then
        //  break;
        }
      else 
        iLevel = target;
      }//end while

    //precip reaction (tank is full)
    double DummyProdNNtl;
    CalcSSurgNNtl(SizeClass, ProdHyPsd, NIntervals, ProdSSurf, DummyProdNNtl);
    double PrecipRate = get_PrecipRate(Prod, ProdSSurf); //!! THE LOOP IS CALCULT. ONLY if PRECIP HAPPENS
    double Btime=0.0;
    if (PrecipRate<0.0)  
      while (Btime < m_dCirculationTime )
        {
        PrecipRate = get_PrecipRate(Prod, ProdSSurf);
        if (sm_bCompletePopulation)
			dt = -0.2/PrecipRate;
		else
			dt = -0.5/PrecipRate;
        if ( (Btime+dt) > m_dCirculationTime)
          dt = m_dCirculationTime - Btime;
        Btime += dt;
        if (sm_bCompletePopulation)
				{
				if (!PrecipBatch(dt, Prod, iLevel, true))// with population balance
					return false;
				}
			else
				{
				if (!PrecipBatchSS(dt, Prod, iLevel))// with SSA
					return false;
				if (sm_bUsePrevPSD)
					{
					//SetPSDfromPrev(Prod);
					}
				}
        //application.processMessages;
        //if flowsheet.UserCancel then
        //  break;
        }

    Prod.AdjustMassTo(MP_All, SlurryTtlMassFlow+LiquorTtlMassFlow);

    HyprodDist2MassFrac(SizeClass, ProdHyPsd, ProdPSD, NIntervals);
    }

  return true;
  } //BatchCycle
Пример #3
0
bool BatchPrecip::PrecipBatch(double dTime, MVector & Prod, double CurLevel, bool AgglomON )
  {
  long m;
  MIBayer & ProdB   = *Prod.GetIF<MIBayer>();
  MIPSD & ProdSz    = *Prod.FindIF<MIPSD>();
  MISSA & ProdSSA   = *Prod.FindIF<MISSA>();
  double TProd = Prod.getT();
  double gpl1 = ProdB.SolidsConc(TProd);
  double ProdVolFlow = Prod.Volume(MP_All);
  double SolidsInitial  = Prod.Mass(MP_Sol);

  double ProdSSurf, ProdNNtl;

  //adjusting the PSD from 1 gpl to real conc....
  for (m=0; m<NIntervals; m++)
    ProdHyPsd[m]= gpl1 * ProdHyPsd[m];

  #if ForceOptimizeOff
  for (m=0; m<NIntervals; m++)
    if (ProdHyPsd[m]<0.0)
      SetStopRequired("Phone Denis, negative PSD!");
  #endif
  CalcSSurgNNtl(SizeClass, ProdHyPsd, NIntervals, ProdSSurf, ProdNNtl);

  //initialise deltaPSD
  for (m=0; m<NIntervals; m++)
    dPSD[m]=0.0;

  //variation of Particles due to Agglomeration by Collision
  const double GRate2 = ProdB.GrowthRate();
  if (AgglomON )
	ApplyAgglom(GRate2, dTime, m_dKvFac, ProdNNtl);

  //variation due to Nucleation in the Smallest Classes ONLY
  const double NRate = get_NucleationRate(m_eNuclModel, Prod, ProdSSurf, m_eShearRate);
  dPSD[0] += NRate*dTime;

  // variation due to Growth Only
  const double GRate3 = ProdB.GrowthRate();
  const double Const_boucle3 = GRate3*dTime/HPDSize;
  dPSD[0] += Const_boucle3*( ProdHyPsd[0]-ProdHyPsd[2] )/2.0;
  for (m=1; m<NIntervals-1; m++)
    dPSD[m] += Const_boucle3*(ProdHyPsd[m-1]-ProdHyPsd[m+1])/2.0;

  // Finally Substr. or Adding Particles to the Each Classes
  for (m=0; m<NIntervals; m++)
    {
    ProdHyPsd[m] += dPSD[m];
    ProdHyPsd[m] = Max(0.0, ProdHyPsd[m]);
    }

  CalcSSurgNNtl(SizeClass, ProdHyPsd, NIntervals, ProdSSurf, ProdNNtl); //Update ProdSSurf and ProdNNtl

  double gpl1x=gpl1;
  gpl1=0.0;
  for (m=0; m<NIntervals; m++)            
    {
    gpl1=gpl1 + ProdHyPsd[m]*pow(SizeClass[m],3)/6E12;
    }
  gpl1 = gpl1 * PI * 2.42;// *ProdVolFlow;

  //readjusting the PSD to 1 gpl...
  for (m=0; m<NIntervals; m++)
    ProdHyPsd[m] = ProdHyPsd[m] / gpl1;

  //=== mass balance ===
  double T0 = Prod.T;
  double Ain2 = ProdB.AluminaConc(C2K(25.0));
  double Cin2 = ProdB.CausticConc(C2K(25.0));
  double ASat2 = ProdB.AluminaConcSat(T0);
  double SSat2 = (Ain2-ASat2)/GTZ(Cin2);
  double NoPerSec2 = ProdSSA.PartNumPerSec();
  double enthIn = Prod.totCp(MP_All) * K2C(T0); // Enthalpie IN

  bool CErr;
  const double Na2OFac = get_Na2OFactor(Prod);

  PerformAluminaSolubility(Prod, dNAN, dNAN, gpl1, 0/*NoPerSec2*/, Na2OFac, SSat2, CErr);

  double T1 = Prod.T;
 
  double SolidsVariation =  (Prod.Mass(MP_Sol) - SolidsInitial); //* 0.97 ;// 0.97 is to compensate for the HYPROD error
 //    mfshydPrev:=mfshyd;
//     mfshyd:=flowtotal*gpl1 -mfsSoda -mfsOxal -mfsSio2 ;the way it was done in HYPROD.. it is WRONG though

  HeatBalance(Prod, SolidsVariation, enthIn, dTime, CurLevel);  // Éliminé pour vérifier la temp ?
  
  return true;
  }