#!/usr/bin/env python # coding: utf-8 # Copyright statement? # # A New 'Transition' # Welcome back! At this point in the course you are all likley aces at numerical analysis, expecially after 5 modules ranging from Diffusion, to Convection, to Conduction, in 1 or 2D, with various Neumann and Dirichlet Boundary conditions! # # But now it's time for a new "phase". In this lesson we begin looking at what happens when your nice rigid boundary conditions decide to start moving on you, essentially creating a moving boundary interface! # # A moving boundary interface is represented by numerous physical behaviors in real-world applications, from the polar ice caps melting, to the phase transformations of metal alloys, to the varying oxygen content of muscles near a clotted bloodvessel [2]. # ![Image](Examples1.jpg) # #### Real World Applications of a Moving Boundary Interface # ### The Stefan Problem # This new type of problem is known as the "Stefan Problem" as it was first studied by Slovene physicist Jozef Stefan around 1890 [3]. Though his focus was primarily on the analysis of ice formations, nowadays his name is synonymous with the particular type of boundary value problem for PDEs where the boundary can move with time. Since the classic Stefan problem concentrated on the temperature distribution of a homogeneous material undergoing a phase transition, one of the most commonly studied Stefan problems today is the melting of Ice to Water! # ![Image](Picture2.jpg) # #### Jozef Stefan pioneered work into phase transitions of materials (ie Ice) # ## A Review: 1D Heat Conduction # Recall from both Modules 2 and 4 we took a loook at the Diffusion equation in 1D: # $$\begin{equation} # \frac{\partial U}{\partial t} = \alpha \frac{\partial^2U}{\partial x^2} # \end{equation}$$ # Where we have the temperature distribution $U(x,t)$ and the thermal diffusivity $\alpha$. While before we looked at the conduction of heat through a graphite rod of length 1 meter, in this scenario we will analyze heat conduction though a 1D rod of ice. Let's first list some basic coefficients associated with the new material: # # ##### Thermal Properties of Ice at ~$0^{\circ}C$: # Thermal Conductivity: $k = 2.22 \frac{W}{mK}$ # # Density: $\rho \approx 1000 \frac{kg}{m^3}$ # # Specific Heat: $c_{p}= 2.05x10^{-3} \frac{J}{kgK}$ # # and lastly, Thermal Diffusivity: $\alpha = \frac{k_{ice}}{\rho_{ice}c_{p_{ice}}} = 1.083x10^{-6} \frac{m^2}{sec}$ # # Melting Temperature of Ice is: $T_{melt}=0^{\circ}C$ # # Okay! With that out of the way, let's look at the temperature distribution across the a rod of ice of length 1m with some basic initial and boundary conditions. For this first scenario, we will not take into account phase transition if temperatures hit $T_{melt}$, and will therefore assume a static boundary condition. # ##### Problem Setup # Governing Equation: $$\begin{equation} # \frac{\partial U}{\partial t} = \alpha \frac{\partial^2U}{\partial x^2} # \end{equation}$$ # # Boundary Conditions: # # LHS: $\frac{\partial U}{\partial x} = -e^{\beta t}$, @x=0, t>0, time-dependant (increasing) heat flux in # # RHS: $\frac{\partial U}{\partial x} = 0$, @x=L, t>0, Insulated end, no heat flux in/out. # # # Initial Conditions: # # $U(x,t) = -10^{\circ}C$, for 00: phase[n]=100 return phase # In[75]: pyplot.plot(x, U, color = '#003366') pyplot.ylabel('Temperature', color ='#003366') Phase1=numpy.ones(nx) Phase=Phase_graph(U, x, nx) pyplot.plot(x, Phase, color = '#654321', ls = '-', lw =3) pyplot.ylim(-12, 10) pyplot.xlim(0, 0.3) pyplot.xlabel('Approx Water-Ice Interface', color = '#654321') # As you can see, the ice SHOULD have melted about 0.07 meters (or 2.75 inches) into our rod. In reality, our boundary interface has moved from x=0 to the right as time elapsed. Not only should our temperature distribution profile change due to the differences in properties ($\rho, k, c_{p}$), but also the feedback from the moving boundary condition. # ## Solutions to the Dimensionless Stefan problem: # ### Analytical Solution: # Before we continue we need to make some simplfications: # # 1) No convection, heat transfer is limited to conduction, # # 2) Pressure is constant, # # 3) Density does not change between the solid and liquid phase (Ice/Water), ie $\rho_{ice}=\rho_{water}\approx 1000 \frac{kg}{m^3}$, # # 4) The phase change interface at $s(t)$ has no thickness # # Looking closer at the problem at hand, we see that our temperature distribution must conform to the below figure: # ![Image](Picture3.jpg) # #### Phase Change Domain # As you can see, our temperature distribution experiences a discontinuity at our solid-liquid interface at x=s(t). Furthermore, this boundary moves to the right as time elapses. If we wish to analyze the distribution in one region or the other, we need to take into account a growing or shrinking domain, and therefore, the boundary of the domain has to be found as part of the solution [2]. In the Melting Problem depicted above, a moving interface separates the liquid and solid phases. The displacement of the boundary interface (denoted as $\dot{s}$) is driven by the heat transport through it [2]. The relationship between the moving interface, s(t), and the temperature distribution through it was developed by and is known as the Stefan Condition (or Stefan Equation) and takes the form of the following boundary conditions: # # when x =s(t), # ###### [1, 3, 2] # $$\dot{s} = \frac{ds}{dt} = -\frac{\partial U}{\partial x}$$ # $$U=0$$ # There are many solution methods for the Stefan problem, for this lesson we will focus on finding the temperature distribution in the liquid region only (ie 00): Location=s[m] # ### Results and Discussions # # Ok! Now lets see what we get, and more importantly, if it makes any sense: # In[80]: XX = numpy.linspace(0, 1, N) Max_tempVGM=max(U0) pyplot.plot(XX,U0, color = '#654322', ls = '--', lw =4) pyplot.xlabel('Length of Domain') pyplot.ylabel('Temperature') pyplot.ylim(-.5, 2) pyplot.xlim(0, 1.0) print('This is our VGM temperature profile after:', nt*dt, 'seconds') print('The temperature at our LHS boundary is:', Max_tempVGM, 'degrees') print('Final position of our interface is:', s[m]) print('The final speed of our interface is:', sdot) print('Our grid spaceing (dx) after', nt*dt, 'seconds is:', dx[m] ) # Hey now! That looks pretty good! Let's compare this result to our earlier Analytical (exact) solution to the 1D Dimensionless problem, for 1 second into the diffusion: # In[81]: pyplot.figure(figsize=(12,10)) pyplot.plot(XX,U0, color = '#654322', ls = '--', lw =4, label = 'Variable Grid Method') pyplot.plot(x, ExactS, color = '#003366', ls = '--', lw =1, label='Analytical Solution') pyplot.xlabel('Length of Domain') pyplot.ylabel('Temperature') pyplot.ylim(0, 1.8) pyplot.xlim(0, 1.0) pyplot.legend(); print('Max error (@x=0) is:',abs(Max_tempVGM - Max_tempA)*(100/Max_tempA),'percent') # Under 2% error is pretty good! What else should we verify? How about the change in the interface location s(t) and the size of our spatial grid (dx) over time? # In[82]: Time=numpy.linspace(0,dt*nt,nt) pyplot.figure(figsize=(10,6)) pyplot.plot(Time,dx, color = '#660033', ls = '--', lw =2, label='Spatial Grid Size') pyplot.plot(Time,s,color = '#222222', ls = '-', lw =4, label='Interface Position, s(t)') pyplot.xlabel('Time (Seconds)') pyplot.ylabel('Length') pyplot.legend(); # and so we see that both the spatial grid size, dx, and the interface location, s(t), increase with time over the course of 1 second. This is exactly what we would expect! Infact, remember back to our anayltical solution, we solved the interface function to be: $s(t)=t$, which is exactly the graph that our numerical solution has given us! # # Well, then! That's a wrap! Looks like everything is all accounted for, right?. . . . . . . . . . . . . .well, not exactly. There are still quite a few questions left unanswered, and now we must discuss the limitations in the Variable Grid Method of numerical implementation. # ### Limitations of the Variable Grid Method # # A number of questions should be coming to mind, among those are: # # 1) Why do we only analyze for 1 second of diffusion? # # 2) Why is your VGM timestep (dt) so small at 2.0e-6? # # 3) Why is your number of spatial grid points (N) only 10? # # # These are all VERY good questions, do you already know the answer? Here is a hint: it all has to do with stability! # # You see, we have a relatively benign stability statement: $\Delta t \leq (\Delta x^{m})^{2}$, but still, it is a crutial aspect of our numerical analysis. This statement limits the size of our timestep, dt, and is the key reason why we chose our initial, constant, dt to be 2.0e-6 (lets not also forget the fact that this dt and N were also chosen by Caldwell and Savovic [5]) . Remember, because we are using a Central Difference scheme, our stability criteria essentially comes from the CFL condition: # # $$\frac{\Delta t}{(\Delta x^{m})^{2}} \leq \sigma = 1$$. # # The parameters dt and dx are not just arbitrarilty chosen. They determine the speed of your numerical solution. At all times you need the speed at which your solution progresses to be faster than the speed at which the problem (in this case, thermal diffusion) propagates. Afterall, how can you calculate the solution numerically when the solution is faster than the numerical analysis?! # # # Here is a pertinent question for you: Which do you determine first: dt, nt, N, or L? Does it matter which one you chose first? # The answer is normally, yes, we chose N and L which gives us dx, we then use a stability statement with dx (and $\alpha$) to limit dt, we then choose our nt to determine the elapsed time into our solution in the form of (nt*dt) seconds, easy right? # # Well this is where we get to limitation #1 with the Variable Grid Method: # # Because the end of our domain "L" is in actuality the position of our interface, s(t), and our interface at time t=0 is approximately at the origin (x=0.02), then if we want a constant number of spatial grids N (say N=10), our initial dx is extremely small!. Remember governing equation (F) says: $\Delta x^{m+1} = \frac{s_{m+1}}{N}$, well at t=0 (m=0) s[0] is 0.02, meaning our initial dx, dx[0] is: 0.002. Plug this back into our stability statement and you see that dt must be smaller than or equal to 4e-6! That is VERY harsh criterion for a timestep dt. In essence, with SUCH a small time step, we would need hundreds of thousands of time loops, nt, in order to get just 1 second of data. Now you see why nt is chosen to be 500,000 in order to get just 1 second of data. If I had wanted more time elapsed, we would have needed iterations in the millions. (This is also why the analytical solution was calculated only for 1 second, we wanted to be able to compare results at the end!) # # Now limitation #2 of the Variable Grid Method: Because the interface starts at the origin, the initial spatial step is very small, and forces a very very small timestep, dt. Thus a very very large number of iterations is needed to get into the "Seconds" scale for simulations, this is a slow numerical process... # # Not only this, but we have limitation #3 of the Variable Grid Method: If we want a longer dimensional domain, we need to choose a larger N. This will give us a final domain of $L=N*dx_{final}$, but if N is larger, then going back to our governing equation (F), $\Delta x^{m+1} = \frac{s_{m+1}}{N}$ this means that dx[0] is even smaller, which continues to force a much smaller dt. Thus for the Variable Grid Method, if you want a large domain, you need an even smaller timestep, which forces more time in your numerical calculation. # # # Let's test this out for ourselves, lets redo the VGM calculations but increase N to say, 14: # (The cell below has the nt set to 500 since we didn't want it to slow you down the first time you ran this program. Notice the N is now 14, go ahead and run this below cellwith nt=500000 and see what happens) # In[83]: dt=2.0e-6 nt=500 #nt=500000 N = 14 Uo=0 U0 = numpy.ones(N)*(Uo) s0=0.02 s=numpy.ones(nt)*(s0) dx=numpy.ones(nt)*(s[1]/N) sdot=(s[1]-s[0])/dt s[1]= s[0] - (dt/(2*dx[0]))*(3*U0[N-1]-4*U0[N-2]+U0[N-3]) dx[0]=(s[1]/N) for m in range(0, nt-1): for i in range(0, N-1): if(i==0): U0[i]= (1-2*(dt/dx[m]**2))*U0[i]+2*(dt/dx[m]**2)*U0[i+1] + \ (2*(dt/dx[m])-dt*(dx[m]*i)*sdot/s[m])*numpy.exp(m*dt) else: U0[i]= U0[i]+ ((dt*(dx[m]*i)*sdot)/(2*dx[m]*s[m]))*(U0[i+1]-U0[i-1])\ +(dt/(dx[m]**2))*(U0[i+1]-2*U0[i]+U0[i-1]) U0[N-1]=0 s[m+1]= s[m] - (dt/(2*dx[m]))*(3*U0[N-1]-4*U0[N-2]+U0[N-3]) sdot=(s[m+1]-s[m])/dt dx[m+1]=(s[m+1]/N) XX = numpy.linspace(0, 1, N) Max_tempVGM=max(U0) pyplot.plot(XX,U0, color = '#654322', ls = '--', lw =4, label = 'VGM') pyplot.plot(x, ExactS, color = '#003366', ls = '--', lw =1, label='Analytical') pyplot.xlabel('Length of Domain') pyplot.ylabel('Temperature') pyplot.ylim(-.5, 2) pyplot.xlim(0, 1.0) pyplot.legend(); print('Time Step dt is:', dt) print('Initial spatial step, dx[0]^2 is:', dx[0]**2 ) print('Max error (@x=0) is:',abs(Max_tempVGM-Max_tempA)*(100/Max_tempA),'Percent') # As you can see, our stability criteria is still met, since $\Delta t \leq (\Delta x_{0})^{2}$. Infact, with a 40% larger N we see that we have less error as well! But what if we set N=15? # (The cell below has the nt set to 500 since we didn't want it to slow you down the first time you ran this program. Notice the N is now 15, go ahead and run this below cellwith nt=500000 and see what happens THIS time...) # In[84]: dt=2.0e-6 nt=500 #nt=500000 N = 15 Uo=0 U0 = numpy.ones(N)*(Uo) s0=0.02 s=numpy.ones(nt)*(s0) dx=numpy.ones(nt)*(s[1]/N) sdot=(s[1]-s[0])/dt s[1]= s[0] - (dt/(2*dx[0]))*(3*U0[N-1]-4*U0[N-2]+U0[N-3]) dx[0]=(s[1]/N) for m in range(0, nt-1): for i in range(0, N-1): if(i==0):U0[i]= (1-2*(dt/dx[m]**2))*U0[i]+2*(dt/dx[m]**2)*U0[i+1]\ +(2*(dt/dx[m])-dt*(dx[m]*i)*sdot/s[m])*numpy.exp(m*dt) else: U0[i]= U0[i]+((dt*(dx[m]*i)*sdot)/(2*dx[m]*s[m]))*(U0[i+1]-U0[i-1])\ +(dt/(dx[m]**2))*(U0[i+1]-2*U0[i]+U0[i-1]) U0[N-1]=0 s[m+1]= s[m] - (dt/(2*dx[m]))*(3*U0[N-1]-4*U0[N-2]+U0[N-3]) sdot=(s[m+1]-s[m])/dt dx[m+1]=(s[m+1]/N) XX = numpy.linspace(0, 1, N) Max_tempVGM=max(U0) pyplot.plot(XX,U0, color = '#654322', ls = '--', lw =4, label = 'VGM') pyplot.plot(x, ExactS, color = '#003366', ls = '--', lw =1, label='Analytical') pyplot.xlabel('Length of Domain') pyplot.ylabel('Temperature') pyplot.ylim(-.5, 2) pyplot.xlim(0, 1.0) pyplot.legend(); print('Time Step dt is:', dt) print('Initial spatial step, dx[0]^2 is:', dx[0]**2 ) print('Max error (@x=0) is:',abs(Max_tempVGM-Max_tempA)*(100/Max_tempA),'Percent') # Wow! That blew up! Just as we expect it would now that with N=15 our time step is larger than our initial spatial step! # #### Final Thoughts # # And now we know, that the Stefan Problem, a boundary value PDE with a time-dependant moving boundary, CAN be solved. We have just demonstrated the solution for a 1D, Dimensionless Stefan Problem with specifically chosen (time-dependant) input heat flux in order to give us a simplified exact solution to compare with. You have also seen implementation of the Variable Grid Method, one of many ways inwhich one can numerical simulate the Stefan problem. But we have also seen the limitations, namely in small time-steps ($dt$), smaller numerical domain ($N\cdot dx_{f}$), and large number of iterations ($nt$) for just a small amount of analytical time (t=$nt \cdot dt$ seconds). Perhaps when it comes time for you to model the melting of the Polar Ice caps, you'll choose a more "expedient" method? Just make sure you get the answer BEFORE the caps melt...) # # EXERCISE #1: Can you implement the Variable Grid Method discretization governing equations to give us a solution faser? Can it handle millions of time iterations without putting us to sleep? (Hint: While governing equations (B) and (C) might be easy to re-write in array form, LHS BC and Moving Interface equations (A), (D), and (E) will not be!) # # EXERCISE #2: Can you write a stability condition statement that will maximize our time-step (dt) for a given N and still keep it constant? # # References # 1. Kutluay S., The numerical solution of one-phase classical Stefan problem, Journal of Computational and Applied Mathematics 81 (1997) 135-144 # # 2. Javierre, E., A Comparison of Numeical Models for one-dimensional Stefan problems, Journal of Compuational and Applied Mathematics 192 (2006) 445-459 # # 3. Vuik, C., "Some historical notes about the Stefan problem". Nieuw Archief voor Wiskunde, 4e serie 11 (2): 157-167 (1993) # # 4. Crowley, A. B., Numerical Solution of Stefan Problems, Brunel University, Department of Mathematics, TR/69 December 1976 # # 5. Caldwell, J., Numerical Solution of Stefan Problem By Variable Space Grid Method and Boundary Immodbilisation Method, Jour. of Mathematical Sciences, Vol. 13 No.1 (2002) 67-79. # In[85]: # Execute this cell to load the notebook's style sheet, then ignore it from IPython.core.display import HTML css_file ='numericalmoocstyle.css' HTML(open(css_file, "r").read())