void CEC_FinalConc::BuildDataDefn(DataDefnBlk & DDB) { Strng T; T.Set("Final Conc %s", m_Spc.m_Name()); DDB.Text (T()); DDEF_Flags VFlags=DDB.GetVisibility(); DDB.String("ExtentType", "", DC_, "", xid_RCTExtentType, &Eq, SetOnChange|isParm, DDBExtentTypes); DDB.SetVisibility(VFlags); if (m_Spc.m_ReactTerm>=0 || m_Spc.m_ProdTerm>=0) { CCnvIndex dc; pchar pCnvTxt; SDB.AddSpCnv(DC_Conc, SDB[m_Spc.m_SpcId].SymOrTag(), "g/L", dc, pCnvTxt); Strng S,C("Rct"),R("Reqd"); if (Valid(m_dRqdTemp)) S.Set("@%.2f", K2C(m_dRqdTemp)); else S="@FinalT"; C+=S; R+=S; m_ddRqdConc.BuildDataDefn(DDB, "Conc_Rqd", "", dc, pCnvTxt, xid_RCTExtent, &Eq, C(), R()); DDB.Double("Conc_MeasTemp", "", DC_T, "C", xid_RCTFinalConcT, &Eq, isResult|noFile|noSnap|InitHidden); DDB.Double("Conc_EOStep", "Conc_Act", DC_, "", &m_dKEOStep, &Eq, isResult); DDB.TagComment(S()); DDB.Double("Conc_Final", "", DC_, "", &m_dKFinal, &Eq, isResult|NAN_OK); DDB.TagComment(S()); DDB.Double("ExtentError", "", DC_Frac, "%", xid_ExtentError, &Eq, isResult|noFile|noSnap|NAN_OK); } };
void MN_Xfer::DumpDerivs() { dbgpln("--Xfr %-12s", FullObjTag()); for (int i = 0; i < NoFlwIOs(); i++) if (IO_In(i)) dbgpln(" In >> :[%14.6g][%14.6g]|[%14.6g] %14.6g %14.3fC %s", IOConduit(i)->QMass(som_SL), IOConduit(i)->QMass(som_Gas) , IOConduit(i)->msHz(), IOConduit(i)->totHf()/GTZ(IOConduit(i)->QMass(som_ALL)), K2C(IOConduit(i)->Temp()), Nd_Rmt(i)->FullObjTag()); for (i = 0; i < NoFlwIOs(); i++) if (IO_Out(i)) dbgpln(" Out << :[%14.6g][%14.6g]|[%14.6g] %14.6g %14.3fC %s", IOConduit(i)->QMass(som_SL), IOConduit(i)->QMass(som_Gas) , IOConduit(i)->msHz(), IOConduit(i)->totHf()/GTZ(IOConduit(i)->QMass(som_ALL)), K2C(IOConduit(i)->Temp()), Nd_Rmt(i)->FullObjTag()); }
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; }
double AirEnth(double T) { ASSERT_RDB(K2C(T)>-106.666666666666 && K2C(T)<70.0000001, "Temperature range problem!", __FILE__, __LINE__); const double Tc = Range(-106.666666666667, K2C(T), 70.0); if (Tc<-45.5555555555557) return 1.0086*Tc + 18.092; //y = 1.0086x + 18.092 if (Tc<-23.3333333333334) return 0.0026*Tc*Tc + 1.2353*Tc + 23.016; //y = 0.0026x2 + 1.2353x + 23.016 if (Tc<-12.2222222222223) return 0.0082*Tc*Tc + 1.4875*Tc + 25.788; //y = 0.0082x2 + 1.4875x + 25.788 if (Tc<0.0000000001) return 0.0199*Tc*Tc + 1.7523*Tc + 27.309; //y = 0.0199x2 + 1.7523x + 27.309 if (Tc<12.2222222222223) return exp(-0.0005*Tc*Tc + 0.0599*Tc + 3.3099); //y = exp(-0.0005x2 + 0.0599x + 3.3099) if (Tc<30.0000000001) return exp(-8E-05*Tc*Tc + 0.0487*Tc + 3.3802); //y = exp(-8E-05x2 + 0.0487x + 3.3802) if (Tc<50.0000001) return exp(-1.51312249 + 0.0000769787611*(Tc+255.676741)*(Tc+255.676741)); //y = exp(-1.51312249 + 0.0000769787611*(x+255.676741)^2) //if (Tc<70.0000001) return exp(3.30966428 + 0.00023039444*(Tc+51.4242508)*(Tc+51.4242508)); //y = exp(3.30966428 + 0.00023039444*(x+51.4242508)^2) }
void CPrecipitator::AdjustT(MStream &Prod) { MVDouble EvapWater (Evap, spWaterVapor); EvapWater = x[3]; double dHeatIn = Feed.totHz(); dReactionHeat = x[iALUMINA]*GibbsiteHOR(K2C(Prod.T)); double newTotDH = m_dOldTotDH*m_dDamping+(m_dTotThermalLoss-dReactionHeat)*(1-m_dDamping); if (iThermalLossMethod==THL_TempDrop) { // Override all other heat loss calcs Prod.T = Feed.T - dTempDropRqd; } else { Prod.Set_totHz(dHeatIn - newTotDH); } m_dOldTotDH = newTotDH; }
void CEC_FinalConc::Parse(CRCTTokenFile &TF) { Clear(); ParseExtent(TF); m_Spc.m_Name=TF.NextToken(); TF.CheckToken("="); m_ddRqdConc.SetVal(GEZ(TF.DoubleToken()), &Eq); m_iFReactTerm=-1; m_iFProdTerm=-1; if (TF.TokenIs("At")) { m_dRqdTemp=GEZ(C2K(TF.DoubleToken())); if (TF.TokenIs("K")) m_dRqdTemp=K2C(m_dRqdTemp); } //ParseDynamic(TF); };
int degree_k2c(u16 k) { return (K2C(k)); }
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; }
//--------------------------------------------------------------------------- // All the precipitation rate calcs are done in this routine // Takes the product composition and calculates rates from this // Rates (in kg/s) are put into global x //--------------------------------------------------------------------------- void CPrecipitator::EvalPrecipRates(MStream & Prod, double T) { T = Prod.T; // May want to do the rate calculation at other temperature MIBayer & ProdB=Prod.IF<MIBayer>(false); MISSA & ProdSSA = Prod.IF<MISSA>(false); dResidenceTime = dTankVol/GTZ(Prod.Volume(MP_SL)); for (int i=0; i<nPRECIPCOMPS; i++) xo[i]=x[i]; // Save old values for convergence test, damping double SAL = ProdSSA.SpecificSurfaceAreaVol(); double SSA = ProdSSA.SpecificSurfaceAreaMass(); double dSSat; if (ProdB.CausticConc(T) > 0) dSSat = (ProdB.AluminaConc(T)-ProdB.AluminaConcSat(T))/ProdB.CausticConc(T); else dSSat = 0.0; if (dSSat < 0) dSSat=0.0; // Supersaturation... switch (iGrowthRateMethod) { case GRM_Fixed: x[iALUMINA] = dGrowthRate; x[1] = x[iBOUND_ORGANICS] = 0.0; break; case GRM_White: { MIBayer & FeedB = Feed.IF<MIBayer>(false); double Ain = FeedB.AluminaConc(T); double Aout = ProdB.AluminaConc(T); dGrowthRateFactor = gF_White*K_White*Exps(-ER_White/T); dGrowthRate = dGrowthRateFactor*Sqr(dSSat); x[iALUMINA] = dGrowthRate*SAL*dTankVol/1000.; double sodaRate = m_dK_Soda*Sqr(dSSat)*Exps(m_dE_Soda/T)*(Aout - Ain)*dTankVol/1000.; if (sodaRate <0.0) sodaRate = 0.0; x[iBOUND_SODA] = sodaRate*(1.0-m_dBndOrgSoda); x[iBOUND_ORGANICS] = sodaRate*m_dBndOrgSoda; } break; case GRM_TTTest: { // Alumina Precipitation.... as per QPRECIPD.cpp MIBayer & FeedB = Feed.IF<MIBayer>(false); double C = ProdB.CausticConc(T); double C25 = ProdB.CausticConc(C2K(25)); double CtoS = ProdB.CtoS(); double S_out = C25/CtoS; // double FC = ProdB.FreeCaustic(T); double FC = ProdB.FreeCaustic(C2K(25)); double ACeq = ProdB.AluminaConcSat(T)/C25; double TOOC=ProdB.TOC(C2K(25))*MW_Na2CO3/MW_C; double a=Exps(-m_dActivationEnergy/T); double b=Exps(-TOOC*m_dk_TOC); double c=Pow(GTZ(S_out), m_dn_s); double d=Pow(GTZ(FC), m_dn_fc); double e=Pow(GTZ(ACeq), m_dn_eq); double K = m_dK0*a*b*c*d*e; double ACout = ProdB.AtoC(); double VLiq = Prod.Volume()*3600.; double MSolids = Prod.MassVector[spTHA]*3600.0/1000.0; double Sol = MSolids*1000.0/GTZ(VLiq); double deltaAC = K * dResidenceTime/3600 * Pow(GTZ(ACout-ACeq),m_dn_) * Pow(GTZ(Sol),m_dn_sol) * Pow(GTZ(m_dSSA),m_dn_ssa); double ACoutEst = dACin - deltaAC; double VolOut = Prod.Volume(MP_Liq, C2K(25.0)); double xx = deltaAC*C25*VolOut*2*MW_Alumina/MW_Al2O3; if (xx<0.0) xx=0.0; x[iALUMINA] = xx; // Bound Soda calculations... slurped from QAL file double k1x = m_dK1 * (0.000598*C25 - 0.00036*K2C(T) + 0.019568*TOOC/C) * (1.0 - 0.758*CtoS); double BoundSoda = k1x * Sqr(ACoutEst-ACeq); if (x[iALUMINA]>=0.0) { double BndSoda = BoundSoda*(x[iALUMINA]*MW_Al2O3/(2.0*MW_THA))*(1.0-m_dBndOrgSoda)*((2.0*MW_NaOH)/MW_Na2O); double BndOrgSoda = BoundSoda*(x[iALUMINA]*MW_Al2O3/(2.0*MW_THA))*(m_dBndOrgSoda)*(MW_OrganicSoda/MW_Na2O); /* If represented as Na2O double BndSoda = BoundSoda*GibbsRate*dBndOrgSoda; double BndOrgSoda = BoundSoda*GibbsRate*(1.0-dBndOrgSoda); */ x[iBOUND_SODA] = BndSoda; x[iBOUND_ORGANICS] = BndOrgSoda; } } break; } return; }