예제 #1
0
//----------------------------------------------------------------------------
int SimplePendulum::Main (int, char**)
{
	msImage = new0 ImageRGB82D(SIZE, SIZE);

	SolveMethod(ExplicitEuler, "Data/explicit.im", "Data/explicit.txt");
	SolveMethod(ImplicitEuler, "Data/implicit.im", "Data/implicit.txt");
	SolveMethod(RungeKutta, "Data/runge.im", "Data/runge.txt");
	SolveMethod(LeapFrog, "Data/leapfrog.im", "Data/leapfrog.txt");
	Stiff1();
	Stiff2True();
	Stiff2Approximate();

	delete0(msImage);
	return 0;
}
예제 #2
0
void BeltCnv::EvalProducts(CNodeEvalIndex & NEI)
  {
  switch (SolveMethod())
    {
    case SM_Direct:
      if (NoProcessJoins()>=1)
        Xfer_EvalProducts(0, Joins[0].Pressure(), NULL, NULL, NULL, NULL, NULL);
      #pragma chFIXIT(Correct conveyor output split in ProBal needs implementing)
      break;
    case SM_Inline:
    case SM_Buffered:
      {
      int Prod=0;
      for (int i=0; i<NoFlwIOs(); i++)
        if (IOId_Self(i)==idProd)
          m_Q.SetProductQmEst(Prod++, IOQmEst_Out(i));
      m_Q.EvalProducts();
      Prod=0;
      for (i=0; i<NoFlwIOs(); i++)
        if (IOId_Self(i)==idProd)
          m_Q.GetProduct(Prod++, IOConduit(i));
      }
      break;
    }
  }
예제 #3
0
파일: M_XFER.CPP 프로젝트: abcweizhuo/Test3
flag MN_Xfer::InitialiseSolution()
  {
  switch (SolveMethod())
    {
    case SM_Direct:
      break;
    case SM_Inline:
    case SM_Buffered:
      if (m_NetworkIsolator)
        m_Accumulator->SetStateAction(IE_SaveState);
      break;
    }

  return 1;
  };
예제 #4
0
파일: M_XFER.CPP 프로젝트: abcweizhuo/Test3
void MN_Xfer::EvalProducts(CNodeEvalIndex & NEI)
  {
  if (NoProcessJoins()>0)
    {
    switch (SolveMethod())
      {
      case SM_Direct:
        if (NoProcessJoins()>0)
          Xfer_EvalProducts(0, Joins[0].Pressure(), &m_QFeed, &m_QProd, GSM(), &m_PCtrl0, &m_BlkEval);
        break;
      case SM_Inline:
      case SM_Buffered:
        {
        if (NoProcessJoins()>=1)
          Xfer_EvalProducts(0, Joins[0].Pressure(), &m_QFeed, &m_QProd, GSM(), NULL, &m_BlkEval);
        }
        break;
      }                
    }
  };
예제 #5
0
파일: ECELL.CPP 프로젝트: abcweizhuo/Test3
void CElectroCell::ConvergeStates(CConvergeStateBlk &CSB)
  {
  ASSERT(NetDynamicMethod());

  if (SolveMethod()==SM_Buffered)
    {

    if (m_RB())
      {//only call this code if the surge is actualy used
      //#if dbgMSurge
      //if (dbgEvalConverge())
      //  dbgpln("CElectroCell::ConvergeStates - RB %s", FullObjTag());
      //#endif

      //double TempKFeed=Contents.Temp();
      double TotHfAtFeedT_Before = Contents.totHf(som_ALL, m_TempKFeed, Contents.Press());

      Contents.SetMeanResTimeCalcsReqd(true);
      m_RB.ConvergeStates(CSB, Contents, Contents.MeanResTimes());

      double TotHfAtFeedT_After = Contents.totHf(som_ALL, m_TempKFeed, Contents.Press());

      double emf = TotHfAtFeedT_After-TotHfAtFeedT_Before;
      emf = (emf / dCellEff);// * -1.0;
      Contents.Set_totHf(Contents.totHf() + emf);

      //#if dbgMSurge
      //if (dbgEvalConverge())
      //  dbgpln("-------------------------------------- ");
      //#endif
      };

    if (!IntegralDone() && !GetActiveHold())
      m_VLE.VFlash(Contents, 0.0, VLEF_Null);//, NULL, NULL, NULL);

    m_EqThermals.ConvergeStates(CSB);
    }
  else
    MN_Surge::ConvergeStates(CSB);
  }
예제 #6
0
파일: ECELL.CPP 프로젝트: abcweizhuo/Test3
/*#F:
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 CElectroCell::EvalProducts(CNodeEvalIndex & NEI)
  {
  StkSpConduit Sd("Sd", chLINEID(), this);
  dCellEff     = Range(0.01, dCellEff, 1.0);
  dPreHeatFrac = Range(0.0, dPreHeatFrac, 1.0);

  switch (SolveMethod())
    {
    case SM_Direct:
      {
      const int iAn = IOWithId_Self(ioidAn);
      const int iCa = IOWithId_Self(ioidCath);
      SpConduit & An = *IOConduit(iAn);
      SpConduit & Ca = *IOConduit(iCa);

      SigmaQInPMin(Sd(), som_ALL, Id_2_Mask(ioidFd));
      m_TempKFeed = Sd().Temp();
  
      const double TotHfAtFeedT_Before = Sd().totHf(som_ALL, m_TempKFeed, Sd().Press());

      m_RB.EvalProducts(Sd());
     
      const double TotHfAtFeedT_After = Sd().totHf(som_ALL, m_TempKFeed, Sd().Press());
      
      if (m_RB())
        {
        // Input energy from the electrical work applied to the cell...
        m_dElecEnergyReact = TotHfAtFeedT_After - TotHfAtFeedT_Before;
        m_dElecEnergyHeat  = (m_dElecEnergyReact/ dCellEff)-m_dElecEnergyReact;
        m_dElecEnergyTotal = m_dElecEnergyReact + m_dElecEnergyHeat;
        
        double dTotHf = Sd().totHf();
        Sd().Set_totHf(dTotHf + m_dElecEnergyTotal); //add remaining energy AFTER reaction
        }
      else
        {
        m_dElecEnergyTotal =  0.0;
        m_dElecEnergyReact =  0.0;
        m_dElecEnergyHeat  =  0.0;
        }

      double Qs = Sd().QMass(som_Sol);
      double Ql = Sd().QMass(som_Liq);
      double Qg = Sd().QMass(som_Gas);
      m_TempKProd = Sd().Temp();

      An.QSetM(Sd(), som_Sol, 0.0, Std_P);
      An.QAddM(Sd(), som_Liq, Ql);
    
      Ca.QSetM(Sd(), som_Sol, Qs, Std_P);
      Ca.QAddM(Sd(), som_Liq, 0.0);

      //put all vapours (if any) to vent (if present)
      const int iVent = IOWithId_Self(ioidVent);
      if (iVent>=0)
        {
        SpConduit & Cvent = *IOConduit(iVent);
        Cvent.QSetM(Sd(), som_Gas, Qg, Std_P);
        }
      else
        {
        An.QAddM(Sd(), som_Gas, Qg); //put vapours somewhere!
        }

      An.SanityCheck();
      Ca.SanityCheck();
      break;
      }
    case SM_Inline:
    case SM_Buffered:
      {
      Contents.ZeroDeriv();
      m_TempKFeed=Sd().Temp();
      if (SolveMethod()==SM_Inline)
        {
        m_RB.EvalProducts(Sd());
        }
      else
        {
        //RB.EvalDerivs(Contents, Sd(), Sd());
        }

      if (m_RB())
        {
        // Input energy from the electrical work applied to the cell...
        m_dElecEnergyReact = m_RB()->HfSumTot();
        m_dElecEnergyHeat  = (m_dElecEnergyReact/ dCellEff)-m_dElecEnergyReact;
        m_dElecEnergyTotal = m_dElecEnergyReact + m_dElecEnergyHeat;
        
        double dTotHf = Sd().totHf();
        Sd().Set_totHf(dTotHf + m_dElecEnergyTotal); //add remaining energy AFTER reaction
        }
      else
        {
        m_dElecEnergyTotal =  0.0;
        m_dElecEnergyReact =  0.0;
        m_dElecEnergyHeat  =  0.0;
        }
      //double emf = 0.0;
      //if (RB())
      //  {
      //  emf = RB()->HfSumTot();
      //  emf = (emf / dCellEff) * -1.0;
      //  Sd().Set_totHf(Sd().totHf() + emf);
      //  }
      //dHeatFlow = emf;

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

      // This prevents any solids leaving with the electrolyte.
      const int ioAn = IOWithId_Self(ioidAn);
      if (ioAn>=0)
        {
        SpMArray AnolyteFilter;
        //Rem.Set(Contents, 0.0, 1.0, 0.0);
        AnolyteFilter.SetToValue(som_Sol, 0.0);
        AnolyteFilter.SetToValue(som_Liq|som_Gas, 1.0);
        SetProdMakeup(PMU_IOId | PMU_Filter, ioidAn, AnolyteFilter, ETemp, Std_P, Contents.Model());
        }

      // This allows the metal and solids to leave in the metal outlet.
      // Solids other than the plated metal leave as sludge.
      const int ioCa = IOWithId_Self(ioidCath);
      if (ioCa>=0)
        {
        SpMArray MetalFilter;
        //Met.Set(Contents, 1.0, 0.0, 0.0);
        MetalFilter.SetToValue(som_Sol, 1.0);
        MetalFilter.SetToValue(som_Liq|som_Gas, 0.0);
        SetProdMakeup(PMU_IOId | PMU_Filter, ioidCath, MetalFilter, ETemp, Std_P, Contents.Model());
        }

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

      m_TempKProd=Sd().Temp();

      break;
      }
    }
  };
예제 #7
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;
      }
    }
  }
예제 #8
0
파일: Ccwash.cpp 프로젝트: abcweizhuo/Test3
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);
    }
  }
예제 #9
0
void CoolingTower::EvalProducts(CNodeEvalIndex & NEI)
  {
  switch (SolveMethod())
    {
    case SM_Direct:
      {
      const int wi = H2OLiq();
      const int si = H2OVap();
      const int ioLiq = IOWithId_Self(ioid_Liq);
      const int ioVap = IOWithId_Self(ioid_Vap);
      const int ioLoss = IOWithId_Self(ioid_LiqLoss);
      const int ioDrift = IOWithId_Self(ioid_DriftLoss);
      
      SpConduit & Ql=*IOConduit(ioLiq);
      SpConduit & Qv=*IOConduit(ioVap);
      
      StkSpConduit QMix("Mix", chLINEID(), this);

      iCycles = Max(2L, iCycles);
      dLGRatio = Range(0.01, dLGRatio, 10.0);
      ClrCI(3);
      ClrCI(4);
      ClrCI(5);
      ClrCI(6);
      dDuty = 0.0;
      SigmaQInPMin(QMix(), som_ALL, Id_2_Mask(ioid_Feed));
      Ql.QCopy(QMix());
      Qv.QCopy(QMix());

      const double QmWaterLiqIn = QMix().VMass[wi];
      const double QmWaterVapIn = QMix().VMass[si];
      const double QmVapIn = QMix().QMass(som_Gas);
      dQmIn = QMix().QMass(som_ALL);
      const flag HasFlw = (dQmIn>UsableMass);
      dTempKFeed = QMix().Temp();
      const double TotHfAtFeedT_Before = QMix().totHf(som_ALL, dTempKFeed, QMix().Press());
      
      //RB.EvalProducts(QMix);
      //EHX.EvalProducts(QMix);

      //double POut = AtmosPress(); //force outlet to Atmos P
      double POut = Std_P; //force outlet to Std_P

      //double AvgCellAgeY=AvgCellAge/(365.25*24.0*60.0*60.0);   
      //double TimeSinceDescaleM=TimeSinceDescale/(365.25*24.0*60.0*60.0/12.0);   
      //double RqdLiqTemp = AirWetBulbT + Approach + AvgCellAgeY*1.1 + TimeSinceDescaleM/12.0*4.0;
      double RqdLiqTemp = dAirWetBulbT + dApproachT;
      double T1 = QMix().Temp();
      double T2 = RqdLiqTemp;
      dLossQm = 0.0;
      bool ValidData;
      switch (iMethod)
        {
        case CTM_Simple: ValidData = (RqdLiqTemp<T1); break;
        case CTM_Merkel: ValidData = (iMerkelCalcType==MCT_TOut ? (dAirWetBulbT<T1) : (RqdLiqTemp<T1)); break;
        }
      if (!HasFlw)
        ValidData = false;
      double RqdLiqTempUsed;
      if (ValidData)
        {
        m_VLE.SetHfInAtZero(QMix());
        if (iMethod==CTM_Simple)
          {
          //const double h1 = QMix().totHf();
          RqdLiqTempUsed = RqdLiqTemp;
          EvapFnd EF(QMix(), RqdLiqTempUsed, POut, m_VLE);//QMix().Press());
          EF.SetTarget(QMix().totHf());
          if (Valid(dEvapFrac))
            {
            EF.SetEstimate(dEvapFrac, 1.0);
            //dEvapFrac = dNAN;
            }
          flag Ok = false;
          dMaxEvapFrac = Range(0.01, dMaxEvapFrac, 1.0);
          int iRet=EF.Start(0.0, dMaxEvapFrac);
          if (iRet==RF_EstimateOK) //estimate is good, solve not required
            {
            Ok = true;
            }
          else
            {
            if (iRet==RF_BadEstimate)
              iRet = EF.Start(0.0, dMaxEvapFrac); // Restart
            if (iRet==RF_OK)
              if (EF.Solve_Brent()==RF_OK)
                Ok = true;
            }
          dEvapFrac = EF.Result(); //use result regardless
          if (!Ok)
            {
            SigmaQInPMin(QMix(), som_ALL, Id_2_Mask(ioid_Feed));
            m_VLE.SetSatPVapFrac(QMix(), dEvapFrac, 0);
            QMix().SetPress(POut);
            RqdLiqTempUsed = QMix().Temp();
            }
          //const double h2 = QMix().totHf();
          //dDuty = h1-h2; this gives 0 (as expected)
          //dDuty is zero because there is no heattransfer with the air
          }
        else
          {
          dAirCp = Max(0.000001, dAirCp);
          dAirWetBulbT = Range(MerkelTMn, dAirWetBulbT, MerkelTMx-10.0);
          if (T1<MerkelTMn || T1>MerkelTMx)
            {
            SetCI(6, true);
            T1 = Range(MerkelTMn, T1, MerkelTMx);
            }

          MerkelTempFnd Fnd(QMix(), *this, T1);
          if (iMerkelCalcType==MCT_KaVL)
            {
            if (T2<MerkelTMn || T2>MerkelTMx)
              {
              SetCI(5, true);
              T2 = Range(MerkelTMn, T2, MerkelTMx);
              RqdLiqTemp = T2;
              }
            dKaVL = Fnd.Function(T2);
            }
          else
            {
            Fnd.SetTarget(dKaVL);
            //Note that for high LG_Ratio (eg>1.0) then ApproachT is higher.

            double Mn = dAirWetBulbT+(T1-dAirWetBulbT)*0.005;
            const double Mx = dAirWetBulbT+(T1-dAirWetBulbT)*0.999;//T1-0.001;
            if (Valid(RqdLiqTemp) && RqdLiqTemp>Mn && RqdLiqTemp<Mx)
              {
              Fnd.SetEstimate(RqdLiqTemp, 1.0);
              //RqdLiqTemp = dNAN;
              }
            flag Ok = false;
            int iRet=Fnd.Start(Mn, Mx);
            if (iRet==RF_EstimateOK) //estimate is good, solve not required
              {
              Ok = true;
              }
            else
              {
              double KaVL_MnTest = Fnd.Function(Mn);
              if (KaVL_MnTest<0.0)
                {
                //Crude fix to find min temp that doesn't cause KaV/L to be negative...
                double fr = 0.01;
                while (KaVL_MnTest<0.0 && fr<0.9)
                  {
                  Mn = dAirWetBulbT+(T1-dAirWetBulbT)*fr;
                  KaVL_MnTest = Fnd.Function(Mn);
                  fr += 0.01;
                  }
                iRet = Fnd.Start(Mn, Mx); // Restart
                }
              if (iRet==RF_OK)
                if (Fnd.Solve_Brent()==RF_OK)
                  Ok = true;
              }
            RqdLiqTemp = Fnd.Result(); //use result regardless
            T2 = RqdLiqTemp;
            if (!Ok)
              {
              const double KaVL_Calc = Fnd.Function(T2);
              SetCI(3, fabs(KaVL_Calc-dKaVL)>1.0e-6);
              }
            dApproachT = RqdLiqTemp - dAirWetBulbT;
            }

          dEvapFactor = Min(dEvapFactor, 0.1); //prevent user from puting a silly large number for this
          dEvapLossQm = dQmIn * dEvapFactor * (C2F(T1)-C2F(T2));//Evaporation Loss: WLe =  Wc * EvapFactor * dT
          dEvapLossQm = Min(dEvapLossQm, QmWaterLiqIn); //limit the amount that can be evaporated


          RqdLiqTempUsed = RqdLiqTemp;

          dEvapFrac = Min(dMaxEvapFrac, (dEvapLossQm+QmWaterVapIn)/GTZ(QmWaterLiqIn+QmWaterVapIn));
          const double h1 = QMix().totHf();
          m_VLE.SetSatPVapFrac(QMix(), dEvapFrac, 0);
          QMix().SetPress(POut);
          QMix().SetTemp(RqdLiqTempUsed);
          const double h2 = QMix().totHf();
          dDuty = h1-h2;

          //dAirEnthOut = AirEnth(T2);
          dAirEnthOut = Fnd.h2 / 0.430210432; //convert from Btu/lb to kJ/kg
          dAirQmIn = dQmIn/dLGRatio;
          dAirTRise = dDuty/GTZ(dAirQmIn)/dAirCp;
          dAirTOut = dAirDryBulbT + dAirTRise;
          dAirMixQm = dAirQmIn + dEvapLossQm;
          const double EvapLossCp = Qv.msCp();
          dAirMixCp = dAirQmIn/GTZ(dAirMixQm)*dAirCp + dEvapLossQm/GTZ(dAirMixQm)*EvapLossCp;
          dAirMixT = dAirQmIn/GTZ(dAirMixQm)*dAirTOut + dEvapLossQm/GTZ(dAirMixQm)*T2;
          }

        double QmWaterVapOut = QMix().VMass[si];
        dQmWaterEvap = Max(0.0, QmWaterVapOut - QmWaterVapIn);
        if (iMethod==CTM_Simple)
          dEvapLossQm=dQmWaterEvap;
        switch (iLossMethod)
          {
          case WLM_None: 
            dDriftLossQm = 0.0;
            dBlowdownLossQm = 0.0;
            dLossQm = 0.0; 
            break;
          case WLM_Frac: 
            dRqdDriftLossFrac = Range(0.0, dRqdDriftLossFrac, 1.0);
            dRqdLossFrac = Range(0.0, dRqdLossFrac, 0.9);
            dLossQm = dQmIn * dRqdLossFrac;
            dDriftLossQm = dLossQm * dRqdDriftLossFrac;
            dBlowdownLossQm = dLossQm - dDriftLossQm;
            break;
          case WLM_Qm: 
            dRqdDriftLossFrac = Range(0.0, dRqdDriftLossFrac, 1.0);
            dLossQm = dRqdLossQm;
            dDriftLossQm = dLossQm * dRqdDriftLossFrac;
            dBlowdownLossQm = dLossQm - dDriftLossQm;
            break;
          case WLM_DriftBlowdown:
            dDriftLossQm = dQmIn * dDriftLossFrac;//Drift Loss: WLd = % of water flow
            dBlowdownLossQm = dEvapLossQm/(iCycles-1);//Blowdown Loss: WLb = WLe / (cycles - 1)
            dLossQm = dDriftLossQm+dBlowdownLossQm;
            break;
          }
        if (dLossQm>dQmIn-dEvapLossQm-QmVapIn)
          {
          SetCI(4, true);
          dLossQm = dQmIn-dEvapLossQm-QmVapIn;
          }
        m_VLE.AddHfOutAtZero(QMix());
        }
      else
        {
        RqdLiqTempUsed = T1;
        dEvapFrac = 0.0;
        dLossQm = 0.0;
        dDriftLossQm = 0.0;
        dBlowdownLossQm = 0.0;
        dEvapLossQm = 0.0;
        dQmWaterEvap = 0.0;
        //if (iMethod==CTM_Merkel)
          {
          dAirEnthOut = TotHfAtFeedT_Before / 0.430210432; //convert from Btu/lb to kJ/kg
          dAirQmIn = 0.0;
          dAirTRise = 0.0;
          dAirTOut = dTempKFeed;
          dAirMixQm = 0.0;
          dAirMixCp = 0.0;
          dAirMixT = dTempKFeed;
          }
        }

      //QMix.ChangeModel(&SMSteamClass);
      const double TotHfAtFeedT_After = QMix().totHf(som_ALL, dTempKFeed, QMix().Press());
      Qv.QSetF(QMix(), som_Gas, 1.0);
      Qv.SetPress(POut);
      Qv.SetTemp(RqdLiqTempUsed);

      const double Qsl = QMix().QMass(som_SL);
      if (ioLoss<0)
        {
        if (ioDrift<0)
          {
          Ql.QSetF(QMix(), som_SL, 1.0);
          Ql.SetPress(POut);
          Ql.SetTemp(RqdLiqTempUsed);
          }
        else
          {
          SpConduit & Qdrift=*IOConduit(ioDrift);
          const double f = dDriftLossQm/GTZ(Qsl);
          Ql.QSetF(QMix(), som_SL, 1.0-f);
          Ql.SetPress(POut);
          Ql.SetTemp(RqdLiqTempUsed);
          Qdrift.QCopy(QMix());
          Qdrift.QSetF(QMix(), som_SL, f);
          Qdrift.SetPress(POut);
          Qdrift.SetTemp(RqdLiqTempUsed);
          }
        }
      else
        {
        SpConduit & Qloss=*IOConduit(ioLoss);
        const double f = dLossQm/GTZ(Qsl);
        Ql.QSetF(QMix(), som_SL, 1.0-f);
        Ql.SetPress(POut);
        Ql.SetTemp(RqdLiqTempUsed);
        if (ioDrift<0)
          {
          Qloss.QCopy(QMix());
          Qloss.QSetF(QMix(), som_SL, f);
          Qloss.SetPress(POut);
          Qloss.SetTemp(RqdLiqTempUsed);
          }
        else
          {
          const double fd = dDriftLossQm/GTZ(Qsl);
          const double fl = f - fd;
          SpConduit & Qdrift=*IOConduit(ioDrift);
          Qdrift.QCopy(QMix());
          Qdrift.QSetF(QMix(), som_SL, fd);
          Qdrift.SetPress(POut);
          Qdrift.SetTemp(RqdLiqTempUsed);
          Qloss.QCopy(QMix());
          Qloss.QSetF(QMix(), som_SL, fl);
          Qloss.SetPress(POut);
          Qloss.SetTemp(RqdLiqTempUsed);
          }
        }

      //results...
      dTotalLossQm = dLossQm+dEvapLossQm;
      dHeatFlow = TotHfAtFeedT_After - TotHfAtFeedT_Before; //what exactly is this???
      dFinalP = Ql.Press();
      dFinalT = Ql.Temp();
      dTempDrop = T1 - dFinalT;
      SetCI(1, HasFlw && RqdLiqTemp>T1);
      SetCI(2, HasFlw && RqdLiqTempUsed>RqdLiqTemp);
      break;
      }
    default:
      MN_Surge::EvalProducts(NEI);
    }
  }