# Converted from whmss.m - Weisz-Hicks multiple steady-state pellet profilesimportnumpyasnpfromscipy.integrateimportsolve_ivp,solve_bvp,quadfromscipy.optimizeimportbrentqfrommiscimportoctave_saveGamma=30.beta=0.4Phiscale=0.01tol=1e-6defintegrand(c,beta,Gamma):returnc*np.exp(Gamma*beta*(1-c)/(1+beta*(1-c)))value,_=quad(lambdac:integrand(c,beta,Gamma),0.,1.,limit=200,epsabs=tol)intercept=np.sqrt(2*value)Phi=intercept*Phiscaleeps_sq=np.sqrt(np.finfo(float).eps)rout=np.linspace(0.,3.,100)defep_fn(ca):denom=1+beta*(1-ca)returnnp.exp(np.clip(Gamma*beta*(1-ca)/np.where(denom>1e-10,denom,1e-10),-500.,500.))defpelletode(r,y):ca,dcadr=y[0],y[1]ep=np.vectorize(ep_fn)(ca)d2=np.where(np.abs(r)<1e-10,Phi**2/3.*ca*ep,-2./r*dcadr+Phi**2*ca*ep)returnnp.vstack([dcadr,d2])defbc(ya,yb):returnnp.array([ya[1],yb[0]-1.])# Shooting to find initial guess for each branchdefpelletode_ivp(r,x):ca,dcadr=x[0],x[1]denom=1+beta*(1-ca)ep=np.exp(Gamma*beta*(1-ca)/denom)ifdenom>1e-10else0.ifr<1e-10:return[dcadr,Phi**2/3.*ca*ep]return[dcadr,-2./r*dcadr+Phi**2*ca*ep]defshoot(c0_val):s=solve_ivp(pelletode_ivp,[0.,3.],[c0_val,0.],method='Radau',rtol=eps_sq,atol=eps_sq)returnfloat(s.y[0,-1])-1.brackets=[(1e-11,1e-10),(0.5,0.7),(0.90,0.99)]results=[]fori,(lo,hi)inenumerate(brackets):c0=brentq(shoot,lo,hi,xtol=1e-12,rtol=1e-12)# get shooting profile on fine mesh as initial guess for solve_bvpr_dense=np.linspace(1e-8,3.,500)sol_shoot=solve_ivp(pelletode_ivp,[r_dense[0],r_dense[-1]],[c0,0.],method='Radau',t_eval=r_dense,rtol=1e-10,atol=1e-12)y_guess=sol_shoot.y# shape (2, N)sol=solve_bvp(pelletode,bc,r_dense,y_guess,tol=1e-6,max_nodes=50000)ifnotsol.success:print(f'Warning: solve_bvp branch {i} did not converge: {sol.message}')conc=sol.sol(rout)[0]temp=beta*(1.-conc)results.append(np.column_stack([rout,conc,temp]))print(f'Branch {i}: c(0)={conc[0]:.6f}, c(R)={conc[-1]:.8f}')octave_save('whmss.dat',('results0',results[0]),('results1',results[1]),('results2',results[2]))