# Converted from leven.m - Levenspiel optimum reactor designimportnumpyasnpfromscipy.integrateimportsolve_ivpfromscipy.optimizeimportfsolvefrommiscimportoctave_saveeps_sq=np.sqrt(np.finfo(float).eps)a=5.;b=0.05c0=5.;conv=0.95d=np.sqrt((1.-2.*b)**2-4.*b*(b+1.))w1=(1.-2.*b+d)/(2.*b)w2=(1.-2.*b-d)/(2.*b)x1=np.sqrt(w1/a)x2=np.sqrt(w2/a)defrxrate(c):returnc/(1.+a*c*c)+b*cc=np.linspace(0.01,10.,300)y=1./rxrate(c)cy=np.column_stack([c,y])# find c1: outlet of first PFR, where r(c1) = r(x2)fixrate=rxrate(x2)c1,_,info,_=fsolve(lambdac:fixrate-rxrate(c),c0,full_output=True)[:4]c1=c1[0]# size first PFR: integrate dc/dt = -1/r(c) from c0 to c1# using c as independent variabledefpfr_dtdc(c,t):return[-1./rxrate(c)]ncs=10cout=np.linspace(c0,c1,ncs)sol=solve_ivp(pfr_dtdc,[c0,c1],[0.],method='Radau',t_eval=cout,rtol=eps_sq,atol=eps_sq,dense_output=False)theta1=sol.y[0,-1]# CSTR: c2 = x2c2=x2theta2=(c1-c2)/rxrate(c2)# size second PFR: c3 = (1-conv)*c0c3=(1.-conv)*c0cout2=np.linspace(c2,c3,ncs)sol2=solve_ivp(pfr_dtdc,[c2,c3],[0.],method='Radau',t_eval=cout2,rtol=eps_sq,atol=eps_sq)theta3=sol2.y[0,-1]# augment cy with special pointscy_extra=np.array([[c0,1./rxrate(c0)],[c1,1./rxrate(c1)],[c2,1./rxrate(c2)],[c3,1./rxrate(c3)]])cy=np.vstack([cy,cy_extra])cy=cy[np.argsort(cy[:,0])]# optimal: PFR(theta1) -> CSTR(theta2) -> PFR(theta3)# segregated reactordefseg(z,x):c_val,ctot=xifz<1.:t=z/(1.-z)# RTD of PFR-CSTR-PFR in seriesift<=theta1+theta3:pr=0.else:pr=np.exp(-(t-(theta1+theta3))/theta2)/theta2dcdz=-rxrate(c_val)/(1.-z)**2dctot=pr*c_val/(1.-z)**2else:dcdz=0.dctot=0.return[dcdz,dctot]npts=50zseg=np.linspace(0.,1.,npts)sol_seg=solve_ivp(seg,[0.,1.],[c0,0.],method='Radau',t_eval=zseg,rtol=eps_sq,atol=eps_sq)csegfin=sol_seg.y[1,-1]# maximum mixednesscinf,_,info_c,_=fsolve(lambdac:c-c0+rxrate(c)*theta2,c0,full_output=True)[:4]cinf=cinf[0]defmm(z,c):t=(1.-z)/zf=0.ift<=theta1+theta3else1./theta2return[-(f*(c[0]-c0)+rxrate(c[0]))/(z*z)]# Start from small epsilon: at z=eps, c=cinf gives dc/dz~0 (cinf is equilibrium),# avoiding the 1/z^2 singularity that trips up Radau at z=0.z_start=1e-4sol_mm=solve_ivp(mm,[z_start,1.],[cinf],method='Radau',t_eval=np.linspace(z_start,1.,npts),rtol=eps_sq,atol=eps_sq)cmmfin=sol_mm.y[0,-1]# build lines tablelines=np.array([[c0,1./rxrate(c0),c1,1./rxrate(c1),c2,1./rxrate(c2),c3,1./rxrate(c3),c1,1./rxrate(c1)],[c0,0.,c1,0.,c2,0.,c3,0.,c2,1./rxrate(c2)]])# region polygonsind1=(cy[:,0]>=c1)&(cy[:,0]<=c0)ind3=(cy[:,0]>=c3)&(cy[:,0]<=c2)regpfr1=np.vstack([cy[ind1],[c0,0.],[c1,0.],[c1,1./rxrate(c1)]])regpfr3=np.vstack([cy[ind3],[c2,0.],[c3,0.],[c3,1./rxrate(c3)]])regcstr2=np.array([[c2,1./rxrate(c2)],[c1,1./rxrate(c1)],[c1,0.],[c2,0.],[c2,1./rxrate(c2)]])octave_save('leven.dat',('cy',cy),('lines',lines),('regpfr1',regpfr1),('regcstr2',regcstr2),('regpfr3',regpfr3))