#pragma rtGlobals=1 // Use modern global access method. // Date: 11/21/2012 //Version 1.2 // This procedure creates a simulation of a particle experiencing a series of random molecular collisions (each of which steps the molecule a mean free path length). // After a defined number of collisions, the particle is at a new, random location. The movement between the starting locations and final location is termed a "displacement". //In the laboratory setting, this is equivalent to the displacement a particle undergoes in between two consecutive frames when imaged with a CCD camera. // A series of random displacements can then be used to estimate Brownian Motion for a particle in 2-D space. // // Written by Josef G. Trapani (jtrapani@amherst.edu) and Ashley R. Carter (acarter@amherst.edu) //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// Menu "Macros" "Simulate Brownian Motion", Start_BM_Panel("start") End //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// Function Start_BM_Panel(ctrlName) String ctrlName String savedDF= GetDataFolder(1) // Remember CDF in a string. DoWindow BM_Panel0 If (V_flag!=0) KillWindow BM_Panel0 SetDataFolder root:BM DoWindow /K BM_histgraph1 DoWindow /K BM_histgraph2 DoWindow /K BM_graph1 DoWindow /K BM_graph2 DoWindow /K BM_graph3 DoWindow /K D_table1 KillWaves /Z /A SetDataFolder savedDF // and restore KillDataFolder /Z root:BM Endif If (cmpstr(ctrlName,"start")==0) NewDataFolder/O/S root:BM Variable /G collisionNum = 99 Variable /G displacementNum = 4500 Variable /G trackNum = 1 Variable /G pathNum = 3 //based on ~3 angstrom = the mean free path length for a bead in water, before it collides with another molecule SetDataFolder savedDF // and restore BM_Panel(ctrlName) Endif End //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// Function BM_Panel(ctrlName) String ctrlName String info = IgorInfo(0) String screen1RectStr = StringByKey("SCREEN1", info) //e.g., "DEPTH=23,RECT=0,0,1280,1024" Variable depth, left, top, right, bottom sscanf screen1RectStr, "DEPTH=%d,RECT=%d,%d,%d,%d", depth, left,top, right, bottom String platform= UpperStr(igorinfo(2)) If (cmpstr(platform,"WINDOWS")==0) NewPanel /N=BM_Panel0 /W=(right-300,top,right,200) /K=2 Else NewPanel /N=BM_Panel0 /W=(right-400,top,right-100,200) /K=2 Endif ModifyPanel /W=BM_Panel0 cbRGB=(62535,62535,62535), frameStyle=3, frameInset=5, noEdit=1, fixedSize=1 SetDrawLayer /W=BM_Panel0 ProgFront DrawRRect /W=BM_Panel0 10,35,290,120 SetDrawEnv /W=BM_Panel0 fsize= 16, fillbgc=(49151,53155,65535) DrawText /W=BM_Panel0 30,65,"2-D Brownian Motion Simulator" SetDrawEnv /W=BM_Panel0 fsize= 10, fillbgc=(49151,53155,65535) Button closeBMPanelbutton,pos={210,10},size={60,20},proc=Start_BM_Panel,title="Close", win=BM_Panel0 SetVariable BMsetvar0,pos={20,160},size={100,15},title="Collisions:", win=BM_Panel0 SetVariable BMsetvar0,fSize=10,limits={1,100000,0},value= root:BM:collisionNum, win=BM_Panel0 SetVariable BMsetvar1,pos={130,160},size={140,15},title="Displacements:", win=BM_Panel0 SetVariable BMsetvar1,fSize=10,limits={1,10000,0},value= root:BM:displacementNum, win=BM_Panel0 SetVariable BMsetvar2,pos={200,130},size={80,15},title="Tracks:", win=BM_Panel0 SetVariable BMsetvar2,fSize=10,limits={1,100,0},value= root:BM:trackNum, win=BM_Panel0 SetVariable BMsetvar3,pos={20,130},size={140,15},title="Mean Free Path:", win=BM_Panel0 SetVariable BMsetvar3,fSize=10,limits={0,100,0},value= root:BM:pathNum, win=BM_Panel0 Button BMbutton0, pos={90,70}, size={120,40}, title="Take a\rrandom walk", proc=runBM, fColor=(65535,54607,32768), win=BM_Panel0 End //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// Function runBM(ctrlName):ButtonControl String ctrlName NVAR numtracks= root:BM:trackNum If (numtracks==1) runBM1(numtracks) Else runBM2(numtracks) Endif End //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// Function runBM1(tempNum) Variable tempNum Variable a,z,f,j NVAR numCollisions= root:BM:collisionNum NVAR numDisplacements= root:BM:displacementNum NVAR numtracks= root:BM:trackNum NVAR numpath= root:BM:pathNum Variable elapsetime, ticktime, i String savedDF= GetDataFolder(1) // Remember CDF in a string. String BM_distances = "root:BM:BM_distances" String BM_XWave = "root:BM:BM_X" String BM_YWave = "root:BM:BM_Y" String BM_XYwave = "root:BM:BM_XYvals" String BMhistwave = "root:BM:BM_stdHist" String histwave = "root:BM:BM_distancesHist" //Make waves to store tally of displacements as consecutive X,Y points String runningBM_XWave = "root:BM:BM_X_tally" String runningBM_YWave = "root:BM:BM_Y_tally" Make /O /N=(numDisplacements) $runningBM_XWave Wave runningBMX = $runningBM_XWave Make /O /N=(numDisplacements) $runningBM_YWave Wave runningBMY = $runningBM_YWave //Make a wave to store each displacement Make /O /N=0 $BM_distances Wave BM_distancesWave = $BM_distances Make /O /N=(numDisplacements) $BM_XWave Wave BMX = $BM_XWave Make /O /N=(numDisplacements) $BM_YWave Wave BMY = $BM_YWave String X_startsum = "root:BM:BM_startXvalues" String X_endsum = "root:BM:BM_endXvalues" Make /O /N=(numDisplacements) $X_startsum Wave xstartsum = $X_startsum Make /O /N=(numDisplacements) $X_endsum Wave xendsum = $X_endsum String Y_startsum = "root:BM:BM_startYvalues" String Y_endsum = "root:BM:BM_endYvalues" Make /O /N=(numDisplacements) $y_startsum Wave ystartsum = $y_startsum Make /O /N=(numDisplacements) $Y_endsum Wave yendsum = $y_endsum //Kill all the graphs DoWindow /K BM_graph1 DoWindow /K BM_graph2 DoWindow /K BM_graph3 DoWindow /K BM_histgraph1 DoWindow /K BM_histgraph2 For (f=0; f for plotting each frame in a separate graph // Display /N=BM_graph1 /K=1 /W=(200,50,600,450 ) $Y_steps vs $X_steps // ModifyGraph rgb=(0,0,0) // ModifyGraph mirror=1 // SetAxis/A/N=1/E=2 left // SetAxis/A/N=1/E=2 bottom //// //// AppendToGraph $Y_start vs $X_start //// ModifyGraph mode($NameOfWave(Ystart))=3,marker($NameOfWave(Ystart))=19, msize($NameOfWave(Ystart))=8 //// ModifyGraph useMrkStrokeRGB($NameOfWave(Ystart))=1 //// ModifyGraph rgb($NameOfWave(Ystart))=(2,39321,1) // // AppendToGraph $Y_end vs $X_end // ModifyGraph mode($NameOfWave(Yend))=3,marker($NameOfWave(Yend))=55, msize($NameOfWave(Yend))=8 // ModifyGraph useMrkStrokeRGB($NameOfWave(Yend))=1 If ((f==0)&&(numtracks==1)) //Display panel to indicate data is loading. NewPanel /N=frameWin1 /FLT=2 /W=(800,400,1000,450) as "Walking..." ModifyPanel cbRGB=(10583,50583,10583), frameStyle=1, NoEdit=1 DrawText 21,20,"Please wait." SetActiveSubwindow _endfloat_ DoUpdate Endif Endfor //EndFor statement for each displacement If ((f==numDisplacements)&&(numtracks==1)) KillWindow frameWin1 // Kill panel Endif //Calculate average length of net BM Variable BM_avgLength = mean(BM_distancesWave) If (numDisplacements!=1) //Concatenate the x and y path lengths (displacements) and then build histogram; mean of lengths shoulbe be equal to zero Concatenate /NP /O {$BM_XWave,$BM_YWave}, $BM_XYwave Make /O /N=100 $BMhistwave Histogram /C /B=1 $BM_XYwave,$BMhistwave Wave newhistwave = $BMhistwave Display /N=BM_histgraph1 /K=1 /W=(600,685,1000,880 ) $BMhistwave ModifyGraph offset($NameOfWave(newhistwave))={-deltaX(newhistwave),0} ModifyGraph mode=5,hbFill=2,rgb=(26214,26214,26214),useBarStrokeRGB=1 Label left "N" Label bottom "Displacement" SetDataFolder root:BM If (numTracks!=1) CurveFit/M=2 /Q=1 /W=2 gauss, $BMhistwave /D Else CurveFit/M=2/W=0 gauss, $BMhistwave /D Endif WAVE W_coef Variable width=W_coef[3] //convert width of histogram to sigma squared (variance) Variable fitVariance = (width/sqrt(2))^2 //Calculate diffusion from MSD (variance) = 2Dt (t = # collisions) //Note nominal D is meanpath^2/2 from k^2 = (2Dt), where k= mean unit of displacement and t =1 collision Variable meanpath = (0+0+numpath^2+numpath^2+(numpath^2)/2+(numpath^2)/2+(numpath^2)/2+(numpath^2)/2)/ 8 Variable Diff = fitVariance/(2*numCollisions) SetDataFolder savedDF TextBox/C/N=textbox2/A=LT /X=0/Y=0 "D = "+num2str(Diff)+"\r\Z08Nominal D = "+num2str(((meanpath)/2)) If (tempNum==numtracks) //Histogram of all displacements Make/N=100/O $histwave Variable binNum =sqrt(numCollisions) Histogram /C /B=1 $BM_distances,$histwave //Display graph of displacements from each random walk taken (total # of displacements; if multiple tracks) Display /N=BM_histgraph2 /K=1 /W=(600,480,1000,675 ) $histwave ModifyGraph mode=5,hbFill=2,rgb=(26214,26214,26214),useBarStrokeRGB=1 TextBox/C/N=textbox2/A=LT /X=0/Y=0 "Histogram of "+num2str(numDisplacements)+" displacements"+"\r\Z10mean displacement = "+num2str(Round(BM_avgLength)) Label left "N" Label bottom "rms displacement" Display /N=BM_graph2 /K=1 /W=(200,480,600,880 ) $Y_endsum vs $X_endsum ModifyGraph rgb=(0,0,0), Mode=2, mirror=1 SetAxis/A/N=1/E=2 left SetAxis/A/N=1/E=2 bottom TextBox/C/N=textbox1/A=RB /X=0/Y=0 num2str(numDisplacements)+" displacements" Label left "ÆY" Label bottom "ÆX" DoUpdate GetAxis left Variable tempMax1 = V_max GetAxis bottom Variable tempMax2 = V_max If (tempMax1