10.34: Numerical Methods Applied to Chemical Engineering Prof. K. Beers Solutions to Problem Set 8: Brownian Dynamics and Monte Carlo SimulationMark Styczynski, Ben Wang Problem 1. Brownian motion in an external field Consider the Brownian motion in the x-direction of a spherical particle of radius Rp and density p moving in a Newtonian fluid of viscosity f. Stokes law gives a drag constant of = 6 f R p . The particle experiences an external potential energy field U(x) such that
the force imparted to the particle by the field is (dU/dx). Let us say that the fluid itself is moving in the x-direction with a velocity vf. With a random force FR(t) due to collisions with individual fluid molecules, Newtons second law of motion for the particle is dv dU + FR (t ) m x = ( vx V f ) dt dx 4 As shown in class, the mass of a particle, m = f R 3 , becomes negligibly small p 3 compared to the drag constant = 6 f R p when Rp is very small. This results inextremely short velocity correlation times p = m
. If we are concerned only with the
observed motion of the particle on scales long compared to p, we can neglect the inertial effects completely by taking the limit m 0 while holding constant. In this limit, the motion of the particle follows dU 0 = ( vx VF ) + FR (t ) dx Upon rearrangement and multiplying by dt, using dx = vxdt, this yields dU 1 dx = V f 1 dt + FR (t )dt dx As shown in class, in the case where vf = 0, U(x) = 0, we get the correct statistical properties of the random displacement by simulating the SDE (Stochastic Differential Equation)dx = ( 2 D ) 2 dWt1
For a finite time step t, we have the simulation algorithmx ( t + t ) x ( t ) = ( 2 D ) 2 Wt1
Wt is a random number generated at each time step with1 P ( ) = e 2 Wt = t 2 Wt is drawn from a normal distribution with a mean of zero and a variance of 2 = t.
Therefore, to agree with this limiting case, we write the SDE for the particle motion in a moving fluid and an external field as 1 dU dx = V f 1 dt + ( 2 D ) 2 dWt dx x( t ) Which yields the simulation algorithm 1 dU x ( t + t ) x ( t ) = V f 1 t ) + ( 2 D ) 2 Wt ( dx x( t ) As shown in class, the drag constant and the diffusivity are related by Einsteins relation kT D= b
Part 1.A. Considering the SDE above, we see that if we had no random force, we would have a dU deterministic velocity of the particle equal to v p = V f 1 . So, the deterministic dx x( t )
(non-random) part of the SDE appears to describe convective motion, and the random part (as we have seen) describes diffusive motion. This appears to suggest that the probability distribution p(t,x) follows a convection/diffusion equation p 2 p = v p p ( t , x ) + D 2 t x x In fact, it is shown in the text that for a system described by the SDE dx = a ( t , x ) dt + b ( t , x ) dWt The probability distribution is governed by a corresponding Fokker-Planck equation 2 1 2 p = a (t, x ) p (t, x ) + 2 x 2 b ( t , x ) p ( t , x ) t x Here, you are asked to perform a number of Brownian dynamics simulations to demonstrate that the probability distribution does indeed follow this convection/diffusion equation in the case of a constant fluid velocity vf and in the absence of an external field, U(x) = 0.
If we release a particle at x = 0 at time t = 0, the initial condition is p(0,x) = (x).1.A.1. First, show that the solution of the convection/diffusion equation isp (t, x ) = 1 ( 2 ) e 22
( x )
= Vf t
2 = 2Dt
Well, note that the question just asks you to show that the solution is such. Thus, Ill only be presenting here a demonstration that this is, indeed, the solution; this will be sufficient for full credit for this part. If you were feeling saucy and decided to actually give a proper derivation, then more power to you.
Looking at the equation p 2 p = v p p ( t , x ) + D 2 t x x
where v p = V f 1
x( t )
We see that all we need to do is take the individual derivatives and make sure that everything cancels. Well use some intuition in our grouping of terms: derivatives of p are likely to equal p times some factor, since there is an exponential term in p. So 1 p ( x Vf t ) = p (t, x ) p (t, x ) 4 Dt 2t t t 2 2 2 1 ( x 2V f tx + V f t ) = p (t, x ) p ( t, x ) 4 Dt 2t t 2 x2 Vf 1 = p (t, x ) 4 Dt 2 4 D 2t 2 2 2 p ( x 2V f tx + V f t ) = p (t, x ) x x 4 Dt p (t, x ) 2 = ( x 2V f tx + V f2t 2 ) 4 Dt x p (t, x ) 2V f t 2 x = ( 2 x 2V f t ) = p ( t , x ) 4Dt 4 Dt 2
2V t 2 x 2 p p = = p (t, x ) f x 2 x x x 4 Dt 2V f t 2 x 1 = p (t, x ) + p (t, x ) 2 Dt 4 Dt Substituting those into the convection/diffusion equation, we get 2 x2 V f2 1 2V f t 2 x 2V f t 2 x 1 = V f p ( t , x ) p (t, x ) + D p ( t, x ) + p (t, x ) 4 Dt 2 4 D 2t 2 Dt 4 Dt 4 Dt We can divide everything through by p(t,x) and simplify the last term to get2 2 2 2 V f2 1 2V f x 2V f t 1 4V f t 8V f xt + 4 x x2 = + 4 Dt 2 4 D 2t 4 Dt 2t 16 Dt 2
Then we clear out the denominators by multiplying through by 4Dt2x 2 V f2t 2 2 Dt = 2V f xt 2V f2t 2 2 Dt + V f2t 2 2V f xt + x 2
Which can be rearranged to yield x 2 2V f2t 2 2 Dt + 2V f xt = x 2 2V f2t 2 2 Dt + 2V f xt Which is a true equation, since all terms cancel out to yield 0 = 0. And yes, it was OK if you used Mathematica or some symbolic calculus program to do all of the manipulations for you, as long as you included that code or screenshots of that
program after it did the calculations for you so that we know you didnt just pull it out of thin air.1.A.2. Next, perform a large number of Brownian dynamics simulations of individual particles for the case D = 1, Vf = 1. Using the MATLAB histogram routines, generate approximate probability distributions p(t,x) at t = 0.5, 1, 2, 3 from the random trajectories x(t) that you generate in the simulations. Plot these vs. the analytical p(t,x) to demonstrate that indeed the Brownian dynamics simulations result in the correct p(t,x). Store your program as username_HW8_1A.m.
OK, so here were just doing a very straightforward problem. You have already been given the simulation equations and the values of all of the appropriate variables. You can either remove the (dU/dx)/ term from your equations in your code, or just set to some arbitrary non-zero number since the zero value of dU/dx will then remove its effect. For Monte Carlo simulations, it is ideal to do a lot of trials. To get a fairly smooth curve, you need to damp out the random fluctuations caused by your sampling. To do that, you should run many trials. For instance, if you are using 50 bins for your histogram and you only run 1000 trials, that the average bin will have 20 occurrences. With such a low frequency, it is easy for random fluctuations to cause slight deviations from the expected distribution. At the same time, though, we would like our programs to run as quickly as possible, so we dont want to run too many trials. One thing to keep in mind for this task is that since we are running the commands in the same loop tens of thousands (or more) times, it behooves us to make only the most necessary commands be in the loop. For instance, if we needlessly re-assign a variable every time through the loop, that will take up extra time. If, on the other hand, we assign the variable outside of the loop, then we can cut down on the computational expense. Similarly, if you use a separate function to calculate your update, it is easiest if you dont bother to unpack your variables. What I mean by this is that if you pass in a bunch of parameters in a structure called Param, and each time you are in the function you say that x = Param.x, y = Param.y, theta = Param.theta, etc., then you are executing each of those thousands of times when they dont really need to be executed. Instead, you should just put Param.x, Param.y, Param.theta, etc., into your function. Though this makes your code harder to read, it makes the program run faster. In fact, this is a consistent pattern throughout computational work: code that is easy to read is frequently suboptimal in execution time. Advanced computer languages and compilers attempt to circumvent these problems for you by intelligently optimizing your code when they assemble your program; in a case like this, though, it pays to note small ways to optimize your code and turn a 90-second execution time into a 10-second execution time. In my code, I have tried for a balance by not outsourcing functions and including them inline in the loops, things may be a little faster than they otherwise might be, though perhaps with a little redundancy in my code. At the same time, though, Im striving for legibility, even at the cost of storing extra variables.
Oh, one final thing to note: you may see that I start off by defining my storage array beforehand. This isnt strictly necessary, as Matlab can automatically extend the array for you. However, each time Matlab tries to extend an array, behind the scenes it is reallocating the array, a rather time-intensive process. This can produce a many-fold, even order-of-magnitude speedup for array that are particularly large. Thats it. The actual coding for this part isnt too tricky. Heres my sample code, and a graph that yours should look something like. The runtime for this program is about 30 seconds. The second figure shows how fewer trials will give the same trend, but with more noise.
% Mark Styczynski % 10.34 % HW 8 % Problem 1.A.2. clear all; close all; % PDL> Set variables. dUdx = 0; D = 1; Vf = 1; deltaT = .001; zeta = 1; % Not needed for now, so set to arbitrary number numTrials = 50000; % PDL> Set initial state and allocate storage