<jupyter_start><jupyter_text>IntroductionThis notebook simulates diffusion of microscopic particles (by solving the Langevin equation). You can interact with the simulation using the various sliders that will appear after you run the last cell.<jupyter_code># Defines a class for the Langevin simulation
class Langevin2D:
    
    # Initializing variables
    def __init__(self, particle_size, mass_density_of_particle, 
                 fluid_viscosity, temperature, initial_velocity):
        self.numparts = 50
        self.meanrad = particle_size * 0.5 * 1e-6
        self.dt = 5e-3
        self.boxsize = np.array([2.2, 1.2])
        self.center = self.boxsize / 2
        self.partden = mass_density_of_particle
        self.flvisc = fluid_viscosity * 1e-5
        self.initvel = initial_velocity
        self.temp = temperature
        self.calc_params()
        self.reset()
        
    # Reseting positions and velocities to zero
    def reset(self):
        self.x = np.ones([self.numparts, 2]) * np.array([0, 1])
        self.p = np.zeros([self.numparts, 2]) 
        self.pmid = np.zeros([self.numparts, 2])
        
    # Calculating useful parameters used in solving the Langevin equation
    def calc_params(self):
        self.partrad = np.random.exponential(self.meanrad, self.numparts)
        self.partmass = self.partden * 1.333 * np.pi * self.partrad**3
        self.stokes = 6.0 * np.pi * self.flvisc * self.partrad
        self.gamma = self.stokes / self.partmass
        self.gravity = self.partmass * 9.81
        self.c1 = np.exp(-self.gamma * self.dt)
        self.c2 = np.sqrt(kb * self.temp * (1 - self.c1**2))
        
    # Run the Langevin update
    def run(self):
        for n in range(self.numparts): 
            self.pmid[n, :] = self.p[n, :] + np.array([0, -self.dt * self.gravity[n] * 0.5])
            self.x[n, :] = self.x[n, :] + self.dt * (self.pmid[n, :] / 2 / self.partmass[n] + [self.initvel, 0])
            self.pmid[n, :] = (self.c1[n] * self.pmid[n, :] + self.c2[n] * 
                               np.random.randn(2) * np.sqrt(self.partmass[n]))
            self.x[n, :] = self.x[n, :] + self.dt * (self.pmid[n, :] / 2 / self.partmass[n] + [self.initvel, 0])
            self.p[n, :] = self.pmid[n, :] + np.array([0, -self.dt * self.gravity[n] * 0.5])
#             self.check_boundary(n)
    
    # Apply sticky boundary conditions 
    def check_boundary(self, n):
        # Applying sticky boundaries
        for i in range(2):
            if self.x[n, i] <  0: 
                self.x[n, i] = 0
            if self.x[n, i] >=  self.boxsize[i]:
                self.x[n, i] = self.boxsize[i]
kb = 1.380e-23  # Boltzmann constant

# Start the Langevin simulation
def start_Langevin_sim(particle_size=10e-6, mass_density_of_particle=1000.0, 
                       fluid_viscosity=9e-4, temperature=300, initial_velocity=1):
    
    # Update arrays for plotting
    def plot_trajectories():
        r1.data_source.data['x'] = l2d.x[:, 0]
        r1.data_source.data['y'] = l2d.x[:, 1]
        push_notebook(handle=target)
    
    # Create langevin class object
    l2d = Langevin2D(particle_size, mass_density_of_particle, fluid_viscosity, temperature, initial_velocity)
    # Initialize figure for plotting trajectories
    p1 = figure(plot_width=800, plot_height=500, tools='',
                x_range=(-0.1, l2d.boxsize[0]), 
                y_range=(0, l2d.boxsize[1]))
    p1.xaxis.axis_label = 'x (m)'
    p1.yaxis.axis_label = 'y (m)'
    p1.toolbar.logo = None
    runtime = 0.25 
    
    # Hack for getting colors dependent on particle size
    colors = ["#%02x%02x%02x" % (int(b), int(g), int(r)) 
              for r, g, b, _ in 255*mpl.cm.Spectral(mpl.colors.Normalize()(l2d.partrad))]
    color_mapper = LinearColorMapper(palette="Spectral10", low=min(l2d.partrad*1e6), high=max(l2d.partrad*1e6))
    color_bar = ColorBar(color_mapper=color_mapper, label_standoff=12, border_line_color=None, location=(0,0))
    
    r1 = p1.scatter(l2d.x[:, 0], l2d.x[:, 1], radius=0.01, fill_color=colors, 
                    fill_alpha=0.4, line_color=colors)
    p1.add_layout(color_bar, 'right')
    target = show(p1, notebook_handle=True)
    # Langevin time-steping loop
    for t in range(int(runtime/l2d.dt)):
        sleep(0.2)
        for n in range(l2d.numparts):
            l2d.run()
            plot_trajectories()
# Interactive controls
style = {'description_width': 'initial'}    
particle_size = widgets.FloatSlider(description='Mean particle diameter (um)', 
                                    style=style, min=0.05, max=5,
                                    step=0.2, value=0.5, continuous_update=False)
mass_density_of_particle = widgets.IntSlider(description='Particle mass density (kg/m^3)', 
                                              style=style, min=500, max=2000, 
                                              step=100, value=1000, continuous_update=False)
fluid_viscosity = widgets.FloatSlider(description='Dynamic viscosity (x10^5 kg/ms)', 
                                      style=style, min=1.8, max=1.9, 
                                      step=0.05, value=1.85, continuous_update=False)
temperature = widgets.IntSlider(description='Temperature (K)', 
                                style=style, min=50, max=600, 
                                step=50, value=300, continuous_update=False)
initial_velocity = widgets.FloatSlider(description='Fluid velocity (m/s)', 
                                       style=style, min=0, max=0.1, 
                                       step=0.01, value=0.05, continuous_update=False)

# Creating the interactive controls ui
widget_ui = widgets.VBox([widgets.HBox([particle_size, mass_density_of_particle]), 
                         widgets.HBox([fluid_viscosity, temperature]), initial_velocity])
widget_out = widgets.interactive_output(start_Langevin_sim, 
                                        {'particle_size': particle_size,
                                         'mass_density_of_particle': mass_density_of_particle,
                                         'fluid_viscosity': fluid_viscosity,
                                         'temperature': temperature,
                                         'initial_velocity': initial_velocity})
# Display the controls and output
display(widget_ui, widget_out)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12182900093955527, 'fraction_numerical': 0.03053554650798622, 'mean_word_length': 2.140117994100295, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 19, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '172067', 'license': 'MIT', 'n_tokens_mistral': 2185, 'n_tokens_neox': 2016, 'n_words': 407, 'path': 'Aerosol-Diffusion.ipynb', 'repo_name': 'nishantsule/Langevin-Dynamics', 'size': '6386'}