├── diffusion ├── HDF5 │ ├── README │ └── README~ ├── images │ └── test │ │ ├── msdmanyensembles.png │ │ ├── deltaxperensemble.png │ │ ├── fitmsdwithlinearsquares.png │ │ └── meansquaredisplacementeperensemble.png ├── runall.jl ├── runhdf5.jl ├── parameters.jl ├── runplots.jl ├── regulartimes.jl ├── makehdf5.jl └── plotfunctions.jl ├── heat ├── differenttimes1000realizations.pdf ├── parameters.jl └── temperatures.jl ├── README.md ├── TODO.md ├── src ├── run.jl ├── Visual.jl ├── HardDiskBilliardSimulation.jl └── HardDiskBilliardModel.jl └── test └── testBilliardModel.jl /diffusion/HDF5/README: -------------------------------------------------------------------------------- 1 | In this folder the hdf5 files will be saved 2 | -------------------------------------------------------------------------------- /diffusion/HDF5/README~: -------------------------------------------------------------------------------- 1 | In this folder the hdf5 files will be saved 2 | -------------------------------------------------------------------------------- /heat/differenttimes1000realizations.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/BilliardwithHardDisks/master/heat/differenttimes1000realizations.pdf -------------------------------------------------------------------------------- /diffusion/images/test/msdmanyensembles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/BilliardwithHardDisks/master/diffusion/images/test/msdmanyensembles.png -------------------------------------------------------------------------------- /diffusion/images/test/deltaxperensemble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/BilliardwithHardDisks/master/diffusion/images/test/deltaxperensemble.png -------------------------------------------------------------------------------- /diffusion/images/test/fitmsdwithlinearsquares.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/BilliardwithHardDisks/master/diffusion/images/test/fitmsdwithlinearsquares.png -------------------------------------------------------------------------------- /diffusion/images/test/meansquaredisplacementeperensemble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/BilliardwithHardDisks/master/diffusion/images/test/meansquaredisplacementeperensemble.png -------------------------------------------------------------------------------- /diffusion/runall.jl: -------------------------------------------------------------------------------- 1 | nameoffile = "test" #It will throw an error if the nameoffile is already exists 2 | nofrealizations = 10 3 | nofensembles = 5 4 | 5 | include("runhdf5.jl") 6 | include("runplots.jl") 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BilliardwithHardDisksScatterers 2 | 3 | The purpose of this program is to simulate the dynamics of a point particle in a board of square cells each with a hard disc inside in sucha a way the particle and the disks can exchange energy. The code is developed in Julia Language and Matplotlib (PyPlot) is used for the visualization. 4 | 5 | To run the program execute `run.jl`. 6 | 7 | **Contributor**: Diego A. Tapias (Faculty of Science, UNAM). 8 | -------------------------------------------------------------------------------- /diffusion/runhdf5.jl: -------------------------------------------------------------------------------- 1 | include("makehdf5.jl") 2 | 3 | parameters = include("parameters.jl") 4 | time = parameters[:t_max] 5 | 6 | ##This parameters have to be given if the file is executed directly 7 | # nofrealizations = 10 8 | # nofensembles = 5 9 | # nameoffile = "test3" 10 | 11 | createhdf5(nameoffile, parameters, nofensembles, nofrealizations) 12 | initializefile!(nameoffile, parameters, nofensembles) 13 | runallrealizations!(nameoffile, nofensembles, nofrealizations) 14 | deltaxandmsd!(nameoffile,nofensembles,nofrealizations) 15 | 16 | #See output at "../HDF5/nameoffile" 17 | -------------------------------------------------------------------------------- /heat/parameters.jl: -------------------------------------------------------------------------------- 1 | using Compat 2 | 3 | @compat Dict(:t_initial => 0, 4 | :t_max => 100, 5 | :radiusdisk => 1.0, 6 | :massdisk => 1.0, 7 | :velocitydisk => 1.0, 8 | :Lx1 => 0, #x position of the first cell 9 | :Ly1 => 0, #y position of the first cell 10 | :windowsize => 0.5, 11 | :massparticle => 1.0, 12 | :size_x => 3., #Size of the cell in x 13 | :size_y => 3., #Size of the cell in y 14 | :velocityparticle => 0.0 15 | ) 16 | -------------------------------------------------------------------------------- /diffusion/parameters.jl: -------------------------------------------------------------------------------- 1 | using Compat 2 | 3 | @compat Dict(:t_initial => 0, 4 | :t_max => 100, 5 | :radiusdisk => 1.0, 6 | :massdisk => 1.0, 7 | :velocitydisk => 1.0, 8 | :Lx1 => 0, #x position of the first cell 9 | :Ly1 => 0, #y position of the first cell 10 | :windowsize => 0.5, 11 | :massparticle => 1.0, 12 | :size_x => 3., #Size of the cell in x 13 | :size_y => 3., #Size of the cell in y 14 | :velocityparticle => 1.0 15 | ) 16 | -------------------------------------------------------------------------------- /diffusion/runplots.jl: -------------------------------------------------------------------------------- 1 | include("plotfunctions.jl") 2 | 3 | pygui(false) #if you want see the plots set it true 4 | 5 | #This parameter have to be given if the file is executed directly. 6 | #nameoffile = "test3" 7 | 8 | a = plotmsdperensemble(nameoffile) 9 | b = plotdeltaxperensemble(nameoffile) 10 | c = fitmsdwithlinearsquares(nameoffile) 11 | d = plotmsdmanyensembles(nameoffile) 12 | 13 | 14 | mkdir("./images/$nameoffile") 15 | a[:savefig]("./images/$nameoffile/meansquaredisplacementeperensemble") 16 | b[:savefig]("./images/$nameoffile/deltaxperensemble") 17 | c[:savefig]("./images/$nameoffile/fitmsdwithlinearsquares") 18 | d[:savefig]("./images/$nameoffile/msdmanyensembles") 19 | -------------------------------------------------------------------------------- /diffusion/regulartimes.jl: -------------------------------------------------------------------------------- 1 | using Docile 2 | 3 | @doc """#xtoregulartimes(simulation_results) 4 | From the simulation results calculate the position of the particle in a time fixed by dtstep 5 | """ -> 6 | function xtoregulartimes(simulation_results, dtstep = 1/4.) 7 | board, particle_xpositions, particle_xvelocities, time = simulation_results 8 | xposition = [particle_xpositions[1]] 9 | nofsteps = int(time[end] * 1/dtstep) 10 | for i in 1:nofsteps 11 | dt = dtstep*i 12 | comparetimes = [dt > t for t in time] 13 | k = findfirst(comparetimes,false) - 1 14 | push!(xposition, particle_xpositions[1+(k-1)] + particle_xvelocities[1+(k-1)]*(dt-time[k])) 15 | end 16 | 17 | xposition, dtstep 18 | end 19 | 20 | # parameters = include("parameters.jl") 21 | # sim = simulation(;parameters...) 22 | # x, t = xtoregulartimes(sim) 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # ¿Qué podemos hacer ahora? 2 | 3 | - Calcular tiempo de residencia promedio de la particulita en una celda 4 | - ¿Dónde está un disco después de tiempo $t$ si no interactúa? 5 | - Desplazamiento cuadrático medio: de la posición y de la energía 6 | - Helfand moments 7 | 8 | - Si la partícula se queda suficiente tiempo en la celda $i$, la distribución de energía entre el disco $i$ y la partícula converge a la microcanónica. Ahí deberíamos poder calcular todo (la distribución de energía que se lleva consigo la partícula cuando sale de la celda, por ejemplo 9 | 10 | - Momento de Helfand para transporte acoplado? 11 | 12 | - Tiempos de vuelo -- su distribución (tiempo sin colisión -- cuando los discos sean suficientemente chicos) 13 | 14 | - Resumen de qué se hizo en cada uno de estos papers clave: 15 | haz un notebook donde se pone una liga al PDF que guardas en el mismo directorio 16 | 17 | - De eso, qué queremos reproducir / mejorar / cambiar? 18 | 19 | - Si se hizo con reservorios, lo podemos hacer sin reservorios? 20 | 21 | - Checar cómo generar procesos continuous con tasas dadas (exponencial) 22 | 23 | - Aprender Gadfly 24 | 25 | ## Mejía-Monasterio, Larralde et al.: 26 | - Green--Kubo para transporte acoplado? 27 | -------------------------------------------------------------------------------- /heat/temperatures.jl: -------------------------------------------------------------------------------- 1 | push!(LOAD_PATH,"../src/") 2 | using HardDiskBilliardSimulation 3 | using PyPlot 4 | 5 | parameters = include("parameters.jl") 6 | nofrealizations = 1000 7 | nofensembles = 1 8 | 9 | time = [100, 1000, 10000] 10 | 11 | fig = plt.figure() 12 | ax = fig[:add_subplot](111) 13 | ax[:set_xlabel]("Number of cell") 14 | ax[:set_ylabel](L"E_{disk}") 15 | 16 | for t in time 17 | parameters[:t_max] = t 18 | for j in 1:nofensembles 19 | dictionary = heatsimulation(;parameters...) 20 | 21 | for i in 2:nofrealizations 22 | dict = heatsimulation(;parameters...); 23 | for disk in keys(dict) 24 | if !haskey(dictionary, disk) 25 | dictionary["$disk"] = dict[disk] 26 | else 27 | push!(dictionary[disk],dict[disk][1]) 28 | end 29 | end 30 | end 31 | 32 | 33 | for disk in keys(dictionary) 34 | push!(dictionary[disk],mean(dictionary[disk])) 35 | end 36 | 37 | cellmeanenergy = [] 38 | numberofcell = [] 39 | 40 | for disk in keys(dictionary) 41 | push!(cellmeanenergy,dictionary[disk][end]) 42 | push!(numberofcell,disk[5:end]) #number associated to the disk string (-2 to "disk-2" for example) 43 | end 44 | 45 | numberofcell = int(numberofcell) 46 | index = sortperm(numberofcell) #sort permutations to plot it connecting points 47 | #in the order of the numberofcell 48 | ax[:plot](numberofcell[index],cellmeanenergy[index],"*--", label = "time$t") 49 | end 50 | handles, labels = ax[:get_legend_handles_labels]() 51 | ax[:legend](handles, labels, loc =1) 52 | end 53 | 54 | -------------------------------------------------------------------------------- /src/run.jl: -------------------------------------------------------------------------------- 1 | ################## 2 | #In this file the main functions of the project are called, 3 | #i.e. *simulation* or *animatedsimulation* from HardDiskBilliardSimulation.jl and *visualize* from 4 | #Visual.jl. 5 | ########################### 6 | 7 | #include("./HardDiskBilliardSimulation.jl") 8 | #include("./Visual.jl") 9 | 10 | push!(LOAD_PATH,"./") 11 | using HardDiskBilliardSimulation 12 | #using Visual 13 | using Compat ## To handle versions less than 0.4 14 | using DataStructures 15 | 16 | visual = false 17 | # To change a parameter, type: parameters[:nameofsymbol] = valueyouwanttoset 18 | parameters = @compat Dict(:t_initial => 0, 19 | :t_max => 100, 20 | :radiusdisk => 1.0, 21 | :massdisk => 1.0, 22 | :velocitydisk => 1.0, 23 | :Lx1 => 0, #x position of the first cell 24 | :Ly1 => 0, #y position of the first cell 25 | :windowsize => 0.5, 26 | :massparticle => 1.0, 27 | :size_x => 3., #Size of the cell in x 28 | :size_y => 3., #Size of the cell in y 29 | :velocityparticle => 1.0 30 | ) 31 | 32 | 33 | #parameters[:t_max] = 1000 34 | 35 | if visual 36 | radiustovisualizeparticle = 0.02 37 | sim = animatedsimulation(;parameters...); 38 | @time visualize(sim, radiustovisualizeparticle); 39 | delta_e_max, = findmax(sim[end]) 40 | delta_e_min, = findmin(sim[end]) 41 | println("Delta_E_max, Delta_E_min = $(delta_e_max),$(delta_e_min)") 42 | time = sim[5] 43 | nofevents = length(time) 44 | println("# of events: $nofevents") 45 | else 46 | parameters[:t_max] = 1000 47 | @time sim = simulation(;parameters...); 48 | board = sim[1] 49 | left = back(board.cells).numberofcell 50 | right = front(board.cells).numberofcell 51 | println("Left-cell, Right-cell: $left,$right") 52 | numberofcells = right + abs(left) + 1 53 | println("# of cells: $numberofcells") 54 | time = sim[3] 55 | nofevents = length(time) 56 | println("# of events: $nofevents") 57 | end 58 | 59 | 60 | 61 | # if (ARGS)[1] != 0 62 | # if ARGS[1] == "true" 63 | # include("./Visual.jl") 64 | # using Visual 65 | # @time visualize(sim, radiustovisualizeparticle); 66 | # end 67 | # end 68 | 69 | #visualize_localenergy(sim); 70 | #just for git 71 | -------------------------------------------------------------------------------- /test/testBilliardModel.jl: -------------------------------------------------------------------------------- 1 | include("../src/HardDiskBilliardModel.jl") 2 | 3 | using HardDiskBilliardModel 4 | using FactCheck 5 | using DataStructures 6 | 7 | facts("Disk tests") do 8 | D = HardDiskBilliardModel.Disk([2.,3.],[4.,6.],6.,4,0) 9 | @fact D.r => [2.0,3.0] 10 | @fact D.v => [4.0,6.0] 11 | @fact D.radius => 6.0 12 | @fact D.mass => 4.0 13 | @fact D.numberofcell => 0 14 | @fact D.lastcollision => 0 15 | end 16 | 17 | 18 | facts("Create Board with Particle test") do 19 | board, particle = create_board_with_particle(0.0,0.0,10.0,10.0,1.0,1.0,1.0,1.0,1.0,0.05) 20 | cell = pop!(board.cells) 21 | @fact cell.walls[1].x => 0.0 22 | @fact cell.walls[2].y => 0.0 23 | @fact cell.walls[3].y => 10.0 24 | @fact cell.walls[4].x => 10.0 25 | 26 | @fact particle.mass => 1.0 27 | @fact particle.numberofcell => 0 28 | end 29 | 30 | facts("Create new cell test") do 31 | cell, particle = HardDiskBilliardModel.create_initial_cell_with_particle(0.0,0.0,10.0,10.0,1.0,1.0,1.0,1.0,1.0,0.05) 32 | cell = HardDiskBilliardModel.create_new_right_cell(cell,particle) 33 | @fact cell.walls[1].x => 10.0 34 | @fact cell.walls[2].y => 0.0 35 | @fact cell.walls[3].y => 10.0 36 | @fact cell.walls[4].x => 20.0 37 | @fact length(cell.walls[4].y) => 4 38 | @fact cell.numberofcell => 1 39 | end 40 | 41 | 42 | facts("Create disk test") do 43 | cell, particle = HardDiskBilliardModel.create_initial_cell_with_particle(10.0,10.0,10.0,10.0,1.0,1.0,1.0,1.0,1.0,0.05) 44 | disk = HardDiskBilliardModel.create_disk(0.0,10,0.0,10.0,0.04,1.0,1.0,0) 45 | 46 | @fact disk.radius => 0.04 47 | @fact disk.mass => 1.0 48 | @fact disk.numberofcell => 0 49 | end 50 | 51 | 52 | facts("Collision Disk-Particle") do 53 | disk = HardDiskBilliardModel.Disk([0.0,0.0],[0.0,0.0],1.0,1.0,0) 54 | particle = HardDiskBilliardModel.Particle([2.0,0.0],[-1.0,0.0],1.0,0) 55 | 56 | @fact HardDiskBilliardModel.dtcollision(particle,disk) => 1.0 57 | end 58 | 59 | 60 | facts("Collision Particle-VerticalSharedWall") do 61 | p1 = HardDiskBilliardModel.Particle([2.0,0.0],[-1.0,0.0],1.0,0) 62 | vw1 = HardDiskBilliardModel.VerticalSharedWall(0.0,[0.0,1.075,2.25,3.],(-1,0)) 63 | p2 = HardDiskBilliardModel.Particle([2.0,0.0],[1.0,0.0],1.0,0) 64 | vw2 = HardDiskBilliardModel.VerticalSharedWall(3.0,[0.0,1.075,2.25,3.],(0,1)) 65 | 66 | 67 | @fact HardDiskBilliardModel.dtcollision(p1,vw1) => 2.0 68 | @fact HardDiskBilliardModel.dtcollision(p2,vw2) => 1.0 69 | end 70 | 71 | 72 | facts("Collision Particle-HorizontalWall") do 73 | p1 = HardDiskBilliardModel.Particle([2.0,1.0],[0,-1.0],1.0,0) 74 | vw1 = HardDiskBilliardModel.HorizontalWall([0.0,3.],0) 75 | p2 = HardDiskBilliardModel.Particle([2.0,1.0],[0.0,1.0],1.0,0) 76 | vw2 = HardDiskBilliardModel.HorizontalWall([0.0,3.],3.) 77 | 78 | 79 | @fact HardDiskBilliardModel.dtcollision(p1,vw1) => 1.0 80 | @fact HardDiskBilliardModel.dtcollision(p2,vw2) => 2.0 81 | end 82 | -------------------------------------------------------------------------------- /diffusion/makehdf5.jl: -------------------------------------------------------------------------------- 1 | push!(LOAD_PATH,"../src/") 2 | 3 | using HDF5 4 | using HardDiskBilliardSimulation 5 | using Docile 6 | 7 | include("regulartimes.jl") 8 | 9 | function createhdf5(nameoffile, parameters, nofensembles, nofrealizations) 10 | h5open("./HDF5/$nameoffile.hdf5", "w") do file 11 | attrs(file)["Nofensembles"] = nofensembles 12 | attrs(file)["Nofrealizations"] = nofrealizations 13 | for (key,value) in parameters 14 | attrs(file)[string(key)] = value 15 | end 16 | end 17 | end 18 | 19 | 20 | 21 | @doc """#initializefile(nameoffile, parameters, nofensembles) 22 | Generate the data for the first particle (realization) in each ensemble according 23 | to the passed parameters."""-> 24 | function initializefile!(nameoffile, parameters, nofensembles) 25 | file = h5open("./HDF5/$nameoffile.hdf5", "r+") 26 | sim = simulation(;parameters...) 27 | x, dt = xtoregulartimes(sim) 28 | lenofarray = length(x) 29 | file["ensemble-1/particle-1/x"] = x 30 | attrs(file["ensemble-1/particle-1"])["Numberofrealization"] = 1 31 | attrs(file)["Δt"] = dt 32 | close(file) 33 | 34 | for j in 2:nofensembles 35 | file = h5open("./HDF5/$nameoffile.hdf5", "r+") 36 | sim = simulation(;parameters...) 37 | x, = xtoregulartimes(sim) 38 | file["ensemble-$j/particle-1/x"] = x 39 | attrs(file["ensemble-$j/particle-1"])["Numberofrealization"] = 1 40 | close(file) 41 | end 42 | end 43 | 44 | 45 | function runallrealizations!(nameoffile, nofensembles, nofrealizations) 46 | for ensemble in 1:nofensembles 47 | if nofrealizations > 1 48 | for realization in 2:nofrealizations 49 | file = h5open("./HDF5/$nameoffile.hdf5", "r+") 50 | sim = simulation(;parameters...) 51 | x, dt = xtoregulartimes(sim) 52 | file["ensemble-$ensemble/particle-$realization/x"] = x 53 | attrs(file["ensemble-$ensemble/particle-$realization"])["Numberofrealization"] = realization 54 | close(file) 55 | end 56 | end 57 | end 58 | end 59 | 60 | @doc """#deltaxandmsd!(nameoffile,nofensembles,nofrealizations) 61 | Returns the value for Δx for each realization and the statistical mean of the msd (mean square displacement) 62 | calculated over the ensemble (that acts like the ensemble in the sense that contains different realizations) """-> 63 | function deltaxandmsd!(nameoffile,nofensembles,nofrealizations) 64 | for ensemble in 1:nofensembles 65 | deltax!("./HDF5/$nameoffile.hdf5", ensemble,nofrealizations) 66 | msd!("./HDF5/$nameoffile.hdf5", ensemble,nofrealizations) 67 | end 68 | end 69 | 70 | @doc """#deltax!(nameoffile, nofensemble,nofrealizations) 71 | Calculates the value of Δx for each realization in the specified number of ensemble"""-> 72 | function deltax!(nameoffile, nofensemble,nofrealizations) 73 | #Initialize for particle-1 (first realization) 74 | file = h5open(nameoffile, "r+") 75 | particle1data = file["ensemble-$nofensemble/particle-1"] 76 | x = read(particle1data,"x") 77 | Δx = x - x[1] 78 | file["ensemble-$nofensemble/particle-1/Δx"] = Δx 79 | close(file) 80 | if nofrealizations > 1 81 | for realization in 2:nofrealizations 82 | file = h5open(nameoffile, "r+") 83 | particle = file["ensemble-$nofensemble/particle-$realization"] 84 | x = read(particle, "x") 85 | Δx = x - x[1] 86 | file["ensemble-$nofensemble/particle-$realization/Δx"] = Δx 87 | close(file) 88 | end 89 | end 90 | end 91 | 92 | 93 | @doc """#msd!(nameoffile, nofensemble,nofrealizations) 94 | Calculates the msd (mean square displacement) of Δx for the specified number of ensemble (the group that contains `nofrealizations` number 95 | of realizations)"""-> 96 | function msd!(nameoffile, nofensemble,nofrealizations) 97 | file = h5open(nameoffile, "r+") 98 | particle1data = file["ensemble-$nofensemble/particle-1"] 99 | x = read(particle1data,"x") 100 | 101 | # length(x) indicates the number of data per realization 102 | 103 | deltax = zeros(length(x)) 104 | deltaxsquare = zeros(length(x)) 105 | 106 | for i in 1:length(x) 107 | Δx = 0.0 108 | Δxsquare = 0.0 109 | for group in file["ensemble-$nofensemble"] 110 | #In this loop add the values for Δx and Δx^2 for all the realizations in a ensemble in a fixed time 111 | particle = read(group) 112 | Δx += particle["Δx"][i] 113 | Δxsquare += particle["Δx"][i]*particle["Δx"][i] 114 | end 115 | deltax[i] = Δx 116 | deltaxsquare[i] = Δxsquare 117 | end 118 | 119 | deltaxpromedio = deltax/nofrealizations 120 | deltaxsquarepromedio = deltaxsquare/nofrealizations 121 | file["ensemble-$nofensemble/meansquaredisplacement/<(Δx)^2>"] = deltaxsquarepromedio 122 | close(file) 123 | end 124 | -------------------------------------------------------------------------------- /diffusion/plotfunctions.jl: -------------------------------------------------------------------------------- 1 | using LinearLeastSquares 2 | using HDF5 3 | using PyPlot 4 | 5 | function gettime(nameoffile) 6 | file = h5open("HDF5/$nameoffile.hdf5","r") 7 | deltat = attrs(file)["Δt"] 8 | tmax = attrs(file)["t_max"] 9 | tmax = read(tmax) 10 | Δt = read(deltat) 11 | t = [0.0:Δt:tmax] 12 | close(file) 13 | t 14 | end 15 | 16 | function getmsdperensemble(nameoffile, nofensemble = 1) 17 | file = h5open("HDF5/$nameoffile.hdf5","r") 18 | msd = file["ensemble-$nofensemble/meansquaredisplacement/"] 19 | msd = read(msd,"<(Δx)^2>") 20 | close(file) 21 | msd 22 | end 23 | 24 | function getnofensembles(nameoffile) 25 | file = h5open("HDF5/$nameoffile.hdf5","r") 26 | nofensembles = attrs(file)["Nofensembles"] 27 | nofensembles = read(nofensembles) 28 | close(file) 29 | nofensembles 30 | end 31 | 32 | function plotmsdperensemble(nameoffile, nofensemble = 1) 33 | fig = plt.figure() 34 | ax = fig[:add_subplot](111) 35 | ax[:set_xlabel]("t") 36 | ax[:set_ylabel](L"$\langle(\Delta x)^2\rangle_t$") 37 | 38 | t = gettime(nameoffile) 39 | msd = getmsdperensemble(nameoffile, nofensemble) 40 | 41 | 42 | ax[:plot](t,msd,".") 43 | fig 44 | end 45 | 46 | function plotdeltaxperensemble(nameoffile, nofensemble = 1, nofparticles = 100) 47 | fig = plt.figure() 48 | ax = fig[:add_subplot](111) 49 | ax[:set_xlabel]("t") 50 | ax[:set_ylabel](L"$\Delta x$") 51 | 52 | t = gettime(nameoffile) 53 | 54 | file = h5open("HDF5/$nameoffile.hdf5","r") 55 | nofrealizations = attrs(file)["Nofrealizations"] 56 | nofrealizations = read(nofrealizations) 57 | 58 | firstrealization = file["ensemble-$nofensemble/particle-1"] 59 | Δx = read(firstrealization,"Δx") 60 | ax[:plot](t,Δx,".") 61 | 62 | if nofrealizations > 1 && nofrealizations > nofparticles 63 | for realization in 2:nofparticles 64 | xdata = file["ensemble-$nofensemble/particle-$realization"] 65 | Δx = read(xdata,"Δx") 66 | ax[:plot](t,Δx,".") 67 | end 68 | 69 | elseif nofrealizations > 1 && nofrealizations < nofparticles 70 | for realization in 2:nofrealizations 71 | xdata = file["ensemble-$nofensemble/particle-$realization"] 72 | Δx = read(xdata,"Δx") 73 | ax[:plot](t,Δx,".") 74 | end 75 | end 76 | fig 77 | end 78 | 79 | 80 | 81 | function fitmsdwithlinearsquares(nameoffile, nofensemble=1) 82 | fig = plt.figure() 83 | ax = fig[:add_subplot](111) 84 | ax[:set_xlabel]("t") 85 | ax[:set_ylabel](L"$\langle(\Delta x)^2\rangle_t$") 86 | 87 | t = gettime(nameoffile) 88 | msd = getmsdperensemble(nameoffile, nofensemble) 89 | 90 | slope = Variable() 91 | intercept = Variable() 92 | line = intercept + t * slope 93 | residuals = line - msd 94 | fit_error = sum_squares(residuals) 95 | optval = minimize!(fit_error) 96 | 97 | slope = evaluate(slope) 98 | intercept = evaluate(intercept) 99 | RSS = evaluate(fit_error) 100 | SYY = sum((msd - mean(msd)).^2) 101 | SS = SYY - RSS 102 | Rsquare = 1 - RSS/SYY 103 | 104 | 105 | corr_text = ax[:text](0.02,0.88,"",transform=ax[:transAxes]) 106 | corr_text[:set_text]("\$R^2\$ = $Rsquare \n slope = $slope \n intercept = $intercept") 107 | ax[:plot](t,msd,"." , label="experimental") 108 | ax[:plot](t, slope*t + intercept, "r.-", label="fit") 109 | handles, labels = ax[:get_legend_handles_labels]() 110 | ax[:legend](handles, labels, loc =4) 111 | 112 | fig 113 | end 114 | 115 | function plotmsdmanyensembles(nameoffile) 116 | fig = plt.figure() 117 | ax = fig[:add_subplot](111) 118 | ax[:set_xlabel]("t") 119 | ax[:set_ylabel](L"$\langle(\Delta x)^2\rangle_t$") 120 | 121 | nofensembles = getnofensembles(nameoffile) 122 | 123 | for ensemble in 1:nofensembles 124 | t = gettime(nameoffile) 125 | msd = getmsdperensemble(nameoffile, ensemble) 126 | ax[:plot](t,msd,".") 127 | end 128 | fig 129 | end 130 | 131 | 132 | 133 | 134 | # fig = plt.figure() 135 | # ax = fig[:add_subplot](111) 136 | # ax[:set_xlabel]("t") 137 | # ax[:set_ylabel](L"$log(\langle\sigma ^2\rangle_t)$") 138 | 139 | # ax[:plot](t,log(variance),"." ) 140 | # fig[:savefig]("./images/Variance/t_max100.0-10000-runssemilog.pdf") 141 | 142 | # fig = plt.figure() 143 | # ax = fig[:add_subplot](111) 144 | # ax[:set_xlabel](L"log(time)") 145 | # ax[:set_ylabel](L"$log(\langle\sigma ^2\rangle_t)$") 146 | 147 | # ax[:plot](log(t),log(variance),"." ) 148 | # fig[:savefig]("./images/Variance/t_max100.0-10000-runsloglog.pdf") 149 | 150 | # fig = plt.figure() 151 | # ax = fig[:add_subplot](111) 152 | # ax[:set_xlabel](L"time \cdot log(time)") 153 | # ax[:set_ylabel](L"$\langle\sigma ^2\rangle_t$") 154 | 155 | # ax[:plot](t .* log(t),variance,"." ) 156 | # fig[:savefig]("./images/Variance/t_max100.0-10000-runslinearithmic.pdf") 157 | 158 | 159 | # fig = plt.figure() 160 | # ax = fig[:add_subplot](111) 161 | # ax[:set_xlabel](L"time") 162 | # ax[:set_ylabel](L"$\frac{\langle\sigma ^2\rangle_t}{t}$") 163 | 164 | # ax[:plot](t,variance ./ t,"." ) 165 | # fig[:savefig]("./images/Variance/t_max100.0-10000-runsvarianceovert.pdf") 166 | -------------------------------------------------------------------------------- /src/Visual.jl: -------------------------------------------------------------------------------- 1 | module Visual 2 | 3 | VERSION < v"0.4-" && using Docile 4 | 5 | using HardDiskBilliardSimulation 6 | using HardDiskBilliardModel 7 | using PyPlot 8 | using PyCall 9 | using DataStructures 10 | 11 | 12 | 13 | export visualize 14 | 15 | pygui(true) 16 | 17 | @pyimport matplotlib.path as mpath 18 | @pyimport matplotlib.patches as patch 19 | @pyimport matplotlib.lines as lines 20 | @pyimport matplotlib.animation as animation 21 | 22 | 23 | 24 | function visualize(simulation_results, radiusparticle) 25 | 26 | board, particle, particle_positions, particle_velocities, time, disk_positions_front, 27 | disk_velocities_front, disk, disk_positions_back,disk_velocities_back, delta_e = simulation_results 28 | 29 | radiusdisk = disk.radius 30 | massparticle = particle.mass 31 | 32 | fig = plt.figure() 33 | ax = fig[:add_subplot](111) 34 | energy_text = ax[:text](0.02,0.88,"",transform=ax[:transAxes]) 35 | time_text = ax[:text](0.60,0.88,"",transform=ax[:transAxes]) 36 | 37 | c = patch.Circle([disk_positions_front[1],disk_positions_front[2]],radiusdisk) 38 | c[:set_color]((rand(),rand(),rand())) 39 | circles = [c] 40 | ax[:add_patch](c) 41 | 42 | c = patch.Circle([disk_positions_back[1],disk_positions_back[2]],radiusdisk) 43 | c[:set_color]((rand(),rand(),rand())) 44 | push!(circles,c) 45 | ax[:add_patch](c) 46 | 47 | p = patch.Circle([particle_positions[1],particle_positions[2]],radiusparticle) 48 | puntual = [p] 49 | ax[:add_patch](p) 50 | plt.gca()[:set_aspect]("equal") 51 | 52 | drawwalls(board, ax) 53 | 54 | function animate(i) 55 | z = [i/10 > t for t in time] 56 | k = findfirst(z,false) - 1 57 | 58 | if k == 0 59 | circles[1][:center] = (disk_positions_front[1],disk_positions_front[2]) 60 | circles[2][:center] = (disk_positions_back[1],disk_positions_back[2]) 61 | p[:center] = (particle_positions[1], particle_positions[2]) 62 | 63 | else 64 | circles[1][:center] = (disk_positions_front[1+2*(k-1)] + disk_velocities_front[1+2*(k-1)]*(i/10-time[k]), disk_positions_front[2+2*(k-1)]+disk_velocities_front[2+2*(k-1)]*(i/10-time[k])) 65 | puntual[1][:center] = (particle_positions[1+2*(k-1)] + particle_velocities[1+2*(k-1)]*(i/10-time[k]), particle_positions[2+2*(k-1)]+particle_velocities[2+2*(k-1)]*(i/10-time[k])) 66 | circles[2][:center] = (disk_positions_back[1+2*(k-1)] + disk_velocities_back[1+2*(k-1)]*(i/10-time[k]), disk_positions_back[2+2*(k-1)]+disk_velocities_back[2+2*(k-1)]*(i/10-time[k])) 67 | e_text = delta_e[k] 68 | t_text = time[k] 69 | energy_text[:set_text]("Delta_E = $(e_text)") 70 | time_text[:set_text]("Time = $(t_text)") 71 | end 72 | 73 | return (puntual, circles, ) 74 | end 75 | 76 | anim = animation.FuncAnimation(fig, animate, frames=int(time[end]*10), interval=20, blit=false, repeat = false) 77 | 78 | end 79 | 80 | 81 | 82 | 83 | function drawwalls(board::Board, ax) 84 | cell = front(board.cells) 85 | label2 = cell.numberofcell 86 | 87 | cell = back(board.cells) 88 | label1 = cell.numberofcell 89 | 90 | size_x = abs(cell.walls[4].x - cell.walls[1].x) 91 | size_y = abs(cell.walls[3].y - cell.walls[2].y) 92 | 93 | ##Notation for lines: from x1,y1, to x2, y2, Line2D([x1,x2],[y1,y2]) 94 | walls = cell.walls 95 | line1 = lines.Line2D([walls[1].x,walls[1].x],[walls[1].y[1],walls[1].y[2]]) 96 | line2 = lines.Line2D([walls[2].x[1],walls[2].x[2]],[walls[2].y,walls[2].y]) 97 | line3 = lines.Line2D([walls[3].x[1],walls[3].x[2]],[walls[3].y,walls[3].y]) 98 | line4 = lines.Line2D([walls[4].x,walls[4].x],[walls[4].y[1],walls[4].y[2]]) 99 | line5 = lines.Line2D([walls[4].x,walls[4].x],[walls[4].y[3],walls[4].y[4]]) 100 | line6 = lines.Line2D([walls[1].x,walls[1].x],[walls[1].y[3],walls[1].y[4]]) 101 | ax[:add_line](line1) 102 | ax[:add_line](line2) 103 | ax[:add_line](line3) 104 | ax[:add_line](line4) 105 | ax[:add_line](line5) 106 | ax[:add_line](line6) 107 | 108 | xmin = walls[1].x 109 | ymin = walls[2].y 110 | ymax = walls[3].y 111 | 112 | numberofcells = abs(label2 - label1)+1 113 | 114 | # if label1 == 0 || label2 == 0 115 | # numberofcells = abs(label2 - label1) + 1 116 | # end 117 | 118 | xmax = walls[4].x + (numberofcells-1)*size_x 119 | 120 | if label1 == -1 121 | xmax = walls[4].x + (numberofcells)*size_x 122 | end 123 | 124 | if numberofcells >= 2 125 | if label1 == -1 126 | line2 = lines.Line2D([walls[2].x[1],walls[2].x[2] + (numberofcells)*size_x],[walls[2].y,walls[2].y]) 127 | line3 = lines.Line2D([walls[3].x[1],walls[3].x[2]+ (numberofcells)*size_x],[walls[3].y,walls[3].y]) 128 | ax[:add_line](line2) 129 | ax[:add_line](line3) 130 | end 131 | 132 | line2 = lines.Line2D([walls[2].x[1],walls[2].x[2] + (numberofcells-1)*size_x],[walls[2].y,walls[2].y]) 133 | line3 = lines.Line2D([walls[3].x[1],walls[3].x[2]+ (numberofcells-1)*size_x],[walls[3].y,walls[3].y]) 134 | ax[:add_line](line2) 135 | ax[:add_line](line3) 136 | 137 | for i in 1:numberofcells 138 | line4 = lines.Line2D([walls[4].x+ i*size_x,walls[4].x+ i*size_x],[walls[4].y[1],walls[4].y[2]]) 139 | line5 = lines.Line2D([walls[4].x+ i*size_x,walls[4].x+ i*size_x],[walls[4].y[3],walls[4].y[4]]) 140 | ax[:add_line](line4) 141 | ax[:add_line](line5) 142 | end 143 | end 144 | 145 | ax[:set_xlim](xmin,xmax) 146 | ax[:set_ylim](ymin,ymax+1.) 147 | end 148 | 149 | 150 | # function localenergy(massdisk,v_disk) 151 | # energy = massdisk*dot(v_disk,v_disk)/2 152 | # end 153 | 154 | 155 | # function update_line(d_vel,k, numberofcells, massdisk) 156 | # x = [1:numberofcells] 157 | # y = zeros(numberofcells) 158 | # for i in 1:numberofcells 159 | # y[i] = localenergy(massdisk, d_vel[i][k]) 160 | # end 161 | # x,y 162 | # end 163 | 164 | end 165 | 166 | -------------------------------------------------------------------------------- /src/HardDiskBilliardSimulation.jl: -------------------------------------------------------------------------------- 1 | include("./HardDiskBilliardModel.jl") 2 | 3 | module HardDiskBilliardSimulation 4 | 5 | #VERSION < v"0.4-" && using Docile 6 | 7 | importall HardDiskBilliardModel 8 | using DataStructures 9 | import Base.isless 10 | importall Base.Collections 11 | export simulation, animatedsimulation, heatsimulation 12 | 13 | #This allows to use the PriorityQueue providing a criterion to select the priority of an Event. 14 | isless(e1::Event, e2::Event) = e1.time < e2.time 15 | 16 | 17 | @doc """#initialcollisions!(board::Board,particle::Particle,t_initial::Real,t_max::Real,pq) 18 | Calculates the initial feasible Events and push them into the PriorityQueue with label `whenwaspredicted` 19 | equal to 0."""-> 20 | function initialcollisions!(board::Board,particle::Particle,t_initial::Real,t_max::Real,pq::PriorityQueue) 21 | whenwaspredicted = 0 22 | for cell in board.cells 23 | enqueuecollisions!(pq, cell.disk,cell, t_initial, whenwaspredicted, t_max) 24 | enqueuecollisions!(pq, particle, cell, t_initial, whenwaspredicted, t_max) 25 | enqueuecollisions!(pq, particle, cell.disk, t_initial, whenwaspredicted, t_max) 26 | end 27 | end 28 | 29 | @doc """#enqueuecollisions!(pq::PriorityQueue,disk::Disk,cell::Cell, t_initial::Real, whenwaspredicted::Int, t_max::Real) 30 | Calculates the feasible events that might occur in a time less than t_max involving a disk and a cell, and push them into the PriorityQueue. """-> 31 | function enqueuecollisions!(pq::PriorityQueue,disk::Disk,cell::Cell, t_initial::Real, whenwaspredicted::Int, t_max::Real) 32 | dt,k = dtcollision(disk,cell) 33 | if t_initial + dt < t_max 34 | enqueue!(pq,Event(t_initial+dt, disk, cell.walls[k],whenwaspredicted),t_initial+dt) 35 | end 36 | end 37 | 38 | @doc """#enqueuecollisions!(pq::PriorityQueue,particle::Particle,cell::Cell, t_initial::Real, whenwaspredicted::Int, t_max::Real) 39 | Calculates the feasible events that might occur in a time less than t_max involving a particle and a cell, and push them into the PriorityQueue. """-> 40 | function enqueuecollisions!(pq::PriorityQueue,particle::Particle,cell::Cell, t_initial::Real, whenwaspredicted::Int, t_max::Real) 41 | dt,k = dtcollision(particle,cell) 42 | if t_initial + dt < t_max 43 | enqueue!(pq,Event(t_initial+dt, particle, cell.walls[k],whenwaspredicted),t_initial+dt) 44 | end 45 | end 46 | 47 | @doc """#enqueuecollisions!(pq::PriorityQueue,particle::Particle,disk::Disk, t_initial::Real, whenwaspredicted::Int, t_max::Real) 48 | Calculates the feasible events that might occur in a time less than t_max involving a particle and a disk, and push them into the PriorityQueue. """-> 49 | function enqueuecollisions!(pq::PriorityQueue,particle::Particle,disk::Disk, t_initial::Real, whenwaspredicted::Int, t_max::Real) 50 | dt = dtcollision(particle,disk) 51 | if t_initial + dt < t_max 52 | enqueue!(pq,Event(t_initial+dt, particle, disk,whenwaspredicted),t_initial+dt) 53 | end 54 | end 55 | 56 | 57 | @doc """#futurecollisions!(::Event,::Board, t_initial::Real,t_max::Real,::PriorityQueue, 58 | whenwaspredicted::Int,:: Particle, isanewcell) 59 | Updates the PriorityQueue pushing into it all the feasible Events that can occur after a valid collision"""-> 60 | function futurecollisions!(event::Event,board::Board, t_initial::Real,t_max::Real,pq::PriorityQueue, 61 | whenwaspredicted::Int,particle::Particle, isanewcell) 62 | ##This loop allows to analyze the cell in which the particle is located. 63 | cell = nothing 64 | for c in board.cells 65 | if c.numberofcell == event.dynamicobject.numberofcell 66 | cell = c 67 | break 68 | end 69 | end 70 | 71 | #This function updates the PriorityQueue taking account that the current event was between a particle and a disk 72 | function future(particle::Particle, disk::Disk) 73 | enqueuecollisions!(pq, particle, cell, t_initial, whenwaspredicted, t_max) 74 | enqueuecollisions!(pq, disk,cell, t_initial, whenwaspredicted, t_max) 75 | 76 | end 77 | 78 | #This function updates the PriorityQueue taking account that the current event was between a particle and a wall 79 | function future(particle::Particle, wall::Wall) 80 | dt,k = dtcollision(particle,cell, wall) 81 | if t_initial + dt < t_max 82 | enqueue!(pq,Event(t_initial+dt, particle, cell.walls[k],whenwaspredicted),t_initial+dt) 83 | end 84 | enqueuecollisions!(pq, particle, cell.disk, t_initial, whenwaspredicted, t_max) 85 | 86 | #If the wall was a VerticalSharedWall that implied to create a new cell, this is invoked 87 | if isanewcell == true 88 | enqueuecollisions!(pq, cell.disk,cell, t_initial, whenwaspredicted, t_max) 89 | end 90 | end 91 | 92 | #This function updates the PriorityQueue taking account that the current event was between a disk and a wall 93 | function future(disk::Disk, wall::Wall) 94 | enqueuecollisions!(pq, disk,cell, t_initial, whenwaspredicted, t_max) 95 | if is_particle_in_cell(particle,cell) 96 | enqueuecollisions!(pq, particle, disk, t_initial, whenwaspredicted, t_max) 97 | end 98 | end 99 | 100 | #Here, the function future is invoked 101 | future(event.dynamicobject,event.diskorwall) 102 | end 103 | 104 | function is_particle_in_cell(p::Particle,c::Cell) 105 | contain = false 106 | if c.numberofcell == p.numberofcell 107 | contain = true 108 | end 109 | contain 110 | end 111 | 112 | 113 | @doc """#validatecollision(event::Event) 114 | Returns true if the event was predicted after the last collision of the Particle and/or of the Disk took place"""-> 115 | function validatecollision(event::Event) 116 | validcollision = false 117 | function validate(d::Disk) 118 | if (event.whenwaspredicted >= event.diskorwall.lastcollision) 119 | validcollision = true 120 | end 121 | end 122 | function validate(w::Wall) 123 | validcollision = true 124 | end 125 | 126 | if event.whenwaspredicted >= event.dynamicobject.lastcollision 127 | validate(event.diskorwall) 128 | end 129 | validcollision 130 | end 131 | 132 | @doc """#updatelabels(::Event,label) 133 | Update the lastcollision label of a Disk and/or a Particle with the label 134 | passed (see *simulation* function)"""-> 135 | function updatelabels(event::Event,label::Int) 136 | #Update both particle and disk 137 | function update(p::Particle,d::Disk) 138 | event.diskorwall.lastcollision = label 139 | event.dynamicobject.lastcollision = label 140 | end 141 | 142 | #update disk 143 | function update(d::Disk,w::Wall) 144 | event.dynamicobject.lastcollision = label 145 | end 146 | 147 | #update particle 148 | function update(p::Particle,w::Wall) 149 | event.dynamicobject.lastcollision = label 150 | end 151 | 152 | update(event.dynamicobject,event.diskorwall) 153 | end 154 | 155 | 156 | @doc """#move(:Board,::Particle,delta_t::Real) 157 | Update the position of all the objects on the board, including the particle, by moving them 158 | an interval of time delta_t"""-> 159 | function move(board::Board,particle::Particle,delta_t::Real) 160 | for cell in board.cells 161 | move(cell.disk,delta_t) 162 | end 163 | move(particle,delta_t) 164 | end 165 | 166 | 167 | @doc """#startsimulation(t_initial, t_max, radiusdisk, massdisk, velocitydisk, massparticle, velocityparticle, Lx1, Ly1, 168 | size_x, size_y, windowsize) 169 | Initialize the important variables to perform the simulation. Returns `board, particle, t, time, pq`. With t equals to t_initial 170 | and time an array initialized with the t value. 171 | """-> 172 | function startsimulation(t_initial::Real, t_max::Real, radiusdisk::Real, massdisk::Real, velocitydisk::Real, 173 | massparticle::Real, velocityparticle::Real, Lx1::Real, Ly1::Real, 174 | size_x::Real, size_y::Real, windowsize::Real) 175 | board, particle = create_board_with_particle(Lx1, Ly1,size_x,size_y,radiusdisk, massdisk, velocitydisk, 176 | massparticle, velocityparticle, windowsize) 177 | pq = PriorityQueue() 178 | enqueue!(pq,Event(0., Particle([0.,0.],[0.,0.],1.0,0),Disk([0.,0.],[0.,0.],1.0,1.0,0), 0),0.) #Just to init pq 179 | initialcollisions!(board,particle,t_initial,t_max,pq) 180 | event = dequeue!(pq) #It's deleted the event at time 0.0 181 | t = event.time 182 | time = [event.time] 183 | return board, particle, t, time, pq 184 | end 185 | 186 | 187 | 188 | 189 | 190 | 191 | @doc """#simulation(t_initial, t_max, radiusdisk, massdisk, velocitydisk, massparticle, velocityparticle, Lx1, Ly1, size_x, size_y,windowsize) 192 | Contains the main loop of the project. The PriorityQueue is filled at each step with Events associated 193 | to a DynamicObject; and the element with the highest physical priority (lowest time) is removed 194 | from the Queue and ignored if it is physically meaningless. The loop goes until the last Event is removed 195 | from the Data Structure, which is delimited by the maximum time(t_max). Just to clarify Lx1 and Ly1 are the coordiantes 196 | (Lx1,Ly1) of the left bottom corner of the initial cell. 197 | 198 | Returns `board, particle, particle_positions, particle_velocities, time`"""-> 199 | function simulation(; t_initial = 0, t_max = 100, radiusdisk = 1.0, massdisk = 1.0, velocitydisk =1.0,massparticle = 1.0, velocityparticle =1.0, 200 | Lx1 = 0., Ly1=0., size_x = 3., size_y = 3.,windowsize = 0.5) 201 | 202 | 203 | board, particle, t, time, pq = startsimulation(t_initial, t_max, radiusdisk, massdisk, velocitydisk, massparticle, velocityparticle, Lx1, Ly1, size_x, size_y, 204 | windowsize) 205 | 206 | 207 | particle_positions, particle_velocities = createparticlelists(particle) 208 | 209 | 210 | #Solo voy a trabajar con la posición en x para analizar la difusión 211 | particle_xpositions = [particle_positions[1]] 212 | particle_xvelocities = [particle_velocities[1]] 213 | # 214 | 215 | label = 0 216 | while(!isempty(pq)) 217 | label += 1 218 | event = dequeue!(pq) 219 | validcollision = validatecollision(event) 220 | if validcollision 221 | updatelabels(event,label) 222 | move(board,particle,event.time-t) 223 | t = event.time 224 | push!(time,t) 225 | new_cell = collision(event.dynamicobject,event.diskorwall, board) #Sólo es un booleano (= true) en el caso de que se cree una nueva celda 226 | e2 = energy(event.dynamicobject,event.diskorwall) 227 | #updateparticlelists!(particle_positions, particle_velocities,particle) 228 | updateparticlexlist!(particle_xpositions, particle_xvelocities, particle) 229 | futurecollisions!(event, board, t,t_max,pq, label, particle, new_cell) 230 | end 231 | end 232 | 233 | push!(time, t_max) 234 | board, particle_xpositions, particle_xvelocities, time 235 | end 236 | 237 | 238 | @doc doc"""#animatedsimulation(t_initial, t_max, radiusdisk, massdisk, velocitydisk, massparticle, velocityparticle, Lx1, Ly1, size_x, size_y,windowsize) 239 | Implements the simulation main loop but adds the storing of the back and front disk positions and velocities, together 240 | with a delta of energy for each collision. 241 | 242 | Returns `board, particle, particle_positions, particle_velocities, time, disk_positions_front, 243 | disk_velocities_front, initialcell.disk, disk_positions_back,disk_velocities_back, delta_e`"""-> 244 | function animatedsimulation(; t_initial = 0, t_max = 100, radiusdisk = 1.0, massdisk = 1.0, velocitydisk =1.0,massparticle = 1.0, velocityparticle =1.0, 245 | Lx1 = 0., Ly1=0., size_x = 3., size_y = 3.,windowsize = 0.5) 246 | board, particle, t, time, pq = startsimulation(t_initial, t_max, radiusdisk, massdisk, velocitydisk, massparticle, velocityparticle, Lx1, Ly1, size_x, size_y, 247 | windowsize) 248 | particle_positions, particle_velocities = createparticlelists(particle) 249 | disk_positions_front, disk_velocities_front, disk_positions_back, disk_velocities_back = creatediskslists(board) 250 | initialcell = front(board.cells) 251 | label = 0 252 | delta_e = [0.] 253 | while(!isempty(pq)) 254 | label += 1 255 | event = dequeue!(pq) 256 | validcollision = validatecollision(event) 257 | ##si se crea una nueva celda cambio el estatus de las variables 258 | if validcollision 259 | updatelabels(event,label) 260 | move(board,particle,event.time-t) 261 | t = event.time 262 | push!(time,t) 263 | e1 = energy(event.dynamicobject,event.diskorwall) 264 | new_cell = collision(event.dynamicobject,event.diskorwall, board) #Sólo es un booleano (= true) en el caso de que se cree una nueva celda 265 | e2 = energy(event.dynamicobject,event.diskorwall) 266 | push!(delta_e, e2 - e1) 267 | updateparticlelists!(particle_positions, particle_velocities,particle) 268 | updatediskslists!(disk_positions_front, disk_velocities_front,front(board.cells)) 269 | updatediskslists!(disk_positions_back,disk_velocities_back,back(board.cells)) 270 | futurecollisions!(event, board, t,t_max,pq, label, particle, new_cell) 271 | end 272 | end 273 | push!(time, t_max) 274 | board, particle, particle_positions, particle_velocities, time, disk_positions_front, disk_velocities_front, initialcell.disk, disk_positions_back,disk_velocities_back, delta_e 275 | end 276 | 277 | function updateparticlexlist!(particle_xpositions,particle_xvelocities, particle::Particle) 278 | push!(particle_xpositions, particle.r[1]) 279 | push!(particle_xvelocities, particle.v[1]) 280 | end 281 | 282 | 283 | function updateparticlelists!(particle_positions, particle_velocities,particle::Particle) 284 | for i in 1:2 285 | push!(particle_positions, particle.r[i]) 286 | push!(particle_velocities, particle.v[i]) 287 | end 288 | end 289 | 290 | function updatediskslists!(disk_positions, disk_velocities,cell::Cell) 291 | for i in 1:2 292 | push!(disk_positions,cell.disk.r[i]) 293 | push!(disk_velocities,cell.disk.v[i]) 294 | end 295 | end 296 | 297 | function createparticlelists(particle::Particle) 298 | particle_positions = [particle.r] 299 | particle_velocities = [particle.v] 300 | particle_positions, particle_velocities 301 | end 302 | 303 | function createdisklists(i) 304 | disk_velocities = [0.0,0.0] 305 | disk_velocities 306 | end 307 | 308 | 309 | function creatediskslists(board::Board) 310 | disk_positions_front = [front(board.cells).disk.r] 311 | disk_velocities_front = [front(board.cells).disk.v] 312 | disk_positions_back = [back(board.cells).disk.r] 313 | disk_velocities_back = [back(board.cells).disk.v] 314 | disk_positions_front, disk_velocities_front, disk_positions_back, disk_velocities_back 315 | end 316 | 317 | @doc """#energy(::Particle,::Wall) 318 | Returns the kinetic energy of a Particle"""-> 319 | function energy(particle::Particle,wall::Wall) 320 | particle.mass*dot(particle.v,particle.v)/2. 321 | end 322 | 323 | @doc """#energy(::Disk,::Wall) 324 | Returns the kinetic energy of a Disk"""-> 325 | function energy(disk::Disk,wall::Wall) 326 | disk.mass*dot(disk.v,disk.v)/2. 327 | end 328 | 329 | @doc """#energy(::Disk,::Wall) 330 | Returns the kinetic energy of a Disk"""-> 331 | function energy(disk::Disk) 332 | disk.mass*dot(disk.v,disk.v)/2. 333 | end 334 | 335 | @doc """#energy(::Particle,::Disk) 336 | Returns the total kinetic energy of a particle and a Disk """-> 337 | function energy(particle::Particle,disk::Disk) 338 | disk.mass*dot(disk.v,disk.v)/2. + particle.mass*dot(particle.v,particle.v)/2. 339 | end 340 | 341 | function heatsimulation(; t_initial = 0, t_max = 100, radiusdisk = 1.0, massdisk = 1.0, velocitydisk =1.0,massparticle = 1.0, velocityparticle =1.0, 342 | Lx1 = 0., Ly1=0., size_x = 3., size_y = 3.,windowsize = 0.5) 343 | 344 | board, particle, t, time, pq = startsimulation(t_initial, t_max, radiusdisk, massdisk, velocitydisk, massparticle, velocityparticle, Lx1, Ly1, size_x, size_y, 345 | windowsize) 346 | 347 | 348 | particle_positions, particle_velocities = createparticlelists(particle) 349 | 350 | disk0_energy = float64([energy(front(board.cells).disk)]) 351 | 352 | dict = Dict("disk0" => disk0_energy) 353 | 354 | 355 | #Solo voy a trabajar con la posición en x para analizar la difusión 356 | particle_xpositions = [particle_positions[1]] 357 | particle_xvelocities = [particle_velocities[1]] 358 | # 359 | 360 | label = 0 361 | while(!isempty(pq)) 362 | label += 1 363 | event = dequeue!(pq) 364 | validcollision = validatecollision(event) 365 | if validcollision 366 | updatelabels(event,label) 367 | move(board,particle,event.time-t) 368 | t = event.time 369 | push!(time,t) 370 | new_cell = collision(event.dynamicobject,event.diskorwall, board) #Sólo es un booleano (= true) en el caso de que se cree una nueva celda 371 | if new_cell == true 372 | dict["disk$(event.dynamicobject.numberofcell)"] = float64([0.0]) 373 | end 374 | 375 | # for k in board.cells 376 | # push!(dict["disk$(k.disk.numberofcell)"],energy(k.disk)) 377 | # end 378 | 379 | #updateparticlelists!(particle_positions, particle_velocities,particle) 380 | updateparticlexlist!(particle_xpositions, particle_xvelocities, particle) 381 | futurecollisions!(event, board, t,t_max,pq, label, particle, new_cell) 382 | end 383 | end 384 | 385 | for k in board.cells 386 | dict["disk$(k.disk.numberofcell)"][1] = energy(k.disk) 387 | end 388 | 389 | push!(time, t_max) #Note that the positions of the disks don't correspond exactly with the position 390 | # at time t_max, but the difference is not important for what we want 391 | dict 392 | end 393 | 394 | 395 | end 396 | -------------------------------------------------------------------------------- /src/HardDiskBilliardModel.jl: -------------------------------------------------------------------------------- 1 | module HardDiskBilliardModel 2 | 3 | ####################################### 4 | #This module contains the needed Types and methods to implement a Simulation of a Billiard 5 | #consisted of a particle that travels along a horizontal board that consists of cells with a 6 | #circumscribed disk that can exchange energy with the particle. 7 | ####################################### 8 | 9 | VERSION < v"0.4-" && using Docile 10 | using Lexicon 11 | using DataStructures 12 | 13 | export Wall, Disk, Event, Cell, Particle, Board, Object, DynamicObject 14 | export create_board_with_particle 15 | export move, dtcollision, collision 16 | 17 | abstract Object 18 | abstract DynamicObject <: Object 19 | abstract Wall <: Object 20 | abstract Vertical <: Wall 21 | 22 | @doc """Type with attributes position(r), velocity(v), mass, numberofcell and lastcollision. This last label has to be 23 | with the main loop of the simulation (see *simulation* in **Simulation.jl**). 24 | ##Example 25 | particle = Particle([0.,0.],[1.,1.],1.0,0,0) 26 | """-> 27 | type Particle <: DynamicObject 28 | r::Array{Real,1} 29 | v::Array{Real,1} 30 | mass::Real 31 | numberofcell::Integer 32 | lastcollision::Integer 33 | end 34 | 35 | Particle(r,v, mass, numberofcell) = Particle(r,v,mass , numberofcell, 0) 36 | 37 | @doc """Type with attributes position(r), velocity(v), radius, mass, numberofcell and lastcollision. This last label has to be 38 | with the main loop of the simulation (see *simulation* in **Simulation.jl**) 39 | ##Example 40 | disk = Disk([0.,0.],[1.,1.],1.0,0,0)"""-> 41 | type Disk <: DynamicObject 42 | r::Array{Real,1} 43 | v::Array{Real,1} 44 | radius::Real 45 | mass::Real 46 | numberofcell::Integer 47 | lastcollision ::Integer 48 | end 49 | 50 | Disk(r,v,radius, mass, numberofcell) = Disk(r,v,radius, mass , numberofcell, 0) 51 | 52 | 53 | @doc """Type that *contains* walls (array of Wall), a disk and a label called numberofcell 54 | ##Example 55 | cell = Cell([wall1,wall2,wall3,wall4],disk,0) 56 | """-> 57 | type Cell 58 | walls::Vector{Wall} 59 | disk::Disk 60 | numberofcell::Integer 61 | end 62 | 63 | #Cell(walls,label) = Cell(walls,label,Disk([-100.,-100.],[0.,0.],0.)) 64 | 65 | @doc doc"""Type that is implemented as a Deque(Double-ended queue) of Cells. It allows to insert 66 | new cells as the particle diffuses 67 | ##Example 68 | board = board = Deque{Cell}(cell) 69 | """-> 70 | type Board 71 | cells::Deque{Cell} 72 | end 73 | 74 | # @doc doc"""Type with attributes x and y. x corresponds to its horizontal position in a Cartesian Plane 75 | # (just a number) and y represents its initial and final height in the Plane (Array of length equal to 2).""" -> 76 | # immutable VerticalWall <: Vertical 77 | # x :: Real 78 | # y :: Array{Real,1} 79 | # end 80 | 81 | @doc doc"""Type with attributes x and y. x corresponds to its horizontal extension in a Cartesian plane 82 | (initial and final position) and y corresponds to its vertical position. 83 | ##Example 84 | HW = HorizontalWall([x1, x2],y) 85 | """ -> 86 | immutable HorizontalWall <:Wall 87 | x :: Array{Real,1} 88 | y :: Real 89 | end 90 | 91 | @doc doc"""Type with attributes x, y and sharedcells. x corresponds to the horizontal position, y is an array that 92 | contains the information of the initial and the final vertical position of the wall and of a window located in the wall. 93 | It is given in the form `[y1wall,y1window,y2window,y2wall]`. 94 | The attribute sharedcells is a tuple that contains the label associated to the cells that share the wall. 95 | ##Example 96 | VW = VerticalSharedWall(0.,[1.,2.,3.,4.],(0,1)) 97 | """-> 98 | immutable VerticalSharedWall <: Vertical 99 | x :: Real 100 | y :: Array{Real,1} #Array of a length greater than the VerticalWall 101 | sharedcells::(Integer,Integer) #Adjacent cells that share the wall 102 | end 103 | 104 | @doc doc"""Type with attributes time, dynamicobject, diskorwall and whenwaspredicted. It is the basic unit of information 105 | for the implementation of a simulation, since it stores the basic information about a collision (what time, with whom and 106 | when was predicted). The last attributte makes reference to the cycle within the main loop in which the event was predicted 107 | (see *simulation* in **Simulation.jl**). 108 | ##Example 109 | `event = Event(10.,particle,horizontalwall,2)` 110 | 111 | It says that in the cycle 2 of the main loop an event (aka collision) is predicted between a particle and a horizontalwall. 112 | It would occur at time 10.0. 113 | """-> 114 | type Event 115 | time :: Real 116 | dynamicobject::DynamicObject #Revisar en el diseño si conviene más tener un sólo objeto 117 | diskorwall ::Object ##tal como cell asociado a un evento y la partícula dentro de cell. 118 | whenwaspredicted:: Integer 119 | end 120 | 121 | @doc """#randuniform(liminf, limsup, dim=1) 122 | Creates an random Array(Vector) of *dimension* dim with limits: liminf, limsup""" -> 123 | function randuniform(liminf, limsup, dim=1) 124 | liminf + rand(dim)*(limsup - liminf) 125 | end 126 | 127 | @doc """#overlap(::Particle,::Disk) 128 | Check if a Particle and a Disk overlap. Return a Boolean"""-> 129 | function overlap(p::Particle, d::Disk) 130 | deltar = d.r - p.r 131 | r = norm(deltar) 132 | return r < d.radius 133 | end 134 | 135 | @doc doc"""#create_particle(Lx1,Lx2,Ly1,Ly2, mass, velocitynorm, numberofcell::Integer) 136 | Creates a Particle with Cartesian coordinates between the boundaries Lx1, Lx2, Ly1, Ly2; and a random velocity 137 | of constant norm. It is worth noting that the passed parameters define corners with Cartesian coordinates: 138 | > (Lx1,Ly1),(Lx1, y2), (Lx2,Ly1), (Lx2,Ly2). 139 | """-> 140 | function create_particle(Lx1::Real,Lx2::Real,Ly1::Real,Ly2::Real, mass::Real, velocitynorm::Real, numberofcell::Integer) 141 | x = randuniform(Lx1, Lx2) 142 | y = randuniform(Ly1, Ly2) 143 | theta = rand()*2*pi 144 | vx = cos(theta)*velocitynorm 145 | vy = sin(theta)*velocitynorm 146 | v = [vx, vy] 147 | Particle([x,y],v, mass, numberofcell,0) 148 | end 149 | 150 | @doc doc"""#create_disk(Lx1,Lx2,Ly1,Ly2, radius, mass, velocitynorm, numberofcell::Integer) 151 | Creates a Disk enclosed in a box with boundaries Lx1, Lx2, Ly1, Ly2; and a random velocity 152 | of constant norm. It is worth noting that the passed parameters define corners with Cartesian coordinates: 153 | > (Lx1,Ly1),(Lx1, y2), (Lx2,Ly1), (Lx2,Ly2). """-> 154 | function create_disk(Lx1::Real,Lx2::Real,Ly1::Real,Ly2::Real,radius::Real, mass::Real, velocitynorm::Real, numberofcell::Integer) 155 | x = randuniform(Lx1 + radius, Lx2 - radius) 156 | y = randuniform(Ly1 + radius, Ly2 - radius) 157 | theta = rand()*2*pi 158 | vx = cos(theta)*velocitynorm 159 | vy = sin(theta)*velocitynorm 160 | v = [vx, vy] 161 | Disk([x,y],v,radius, mass,numberofcell) 162 | end 163 | 164 | @doc """#create_window(Ly1, Ly2, windowsize) 165 | Returns the extrema y-coordinates for a window with size windowsize centered between Ly1 and Ly2 (regardless of 166 | the x-coordinate). 167 | """-> 168 | function create_window(Ly1::Real, Ly2::Real, windowsize::Real) 169 | Ly3 = Ly1 + (Ly2 - Ly1)/2. - windowsize/2. 170 | Ly4 = Ly3 + windowsize 171 | Ly3, Ly4 172 | end 173 | 174 | @doc """#create_initial_cell_with_particle( Lx1, Ly1,size_x,size_y,radiusdisk, massdisk, velocitydisk, 175 | massparticle, velocityparticle, windowsize) 176 | Creates an instance of Cell. Size of its sides and initial coordinates for the left down corner are passed (Lx1,Ly1) 177 | together with the needed data to create the embedded disk and a particle inside the cell."""-> 178 | function create_initial_cell_with_particle( Lx1::Real, Ly1::Real,size_x::Real,size_y::Real,radiusdisk, 179 | massdisk::Real, velocitydisk::Real, 180 | massparticle::Real, velocityparticle::Real, windowsize::Real) 181 | Lx2 = Lx1 + size_x 182 | Ly2 = Ly1 + size_y 183 | Ly3, Ly4 = create_window(Ly1, Ly2, windowsize) 184 | nofcell = 0 185 | leftsharedwall = VerticalSharedWall(Lx1,[Ly1,Ly3,Ly4,Ly2],(nofcell,nofcell-1)) 186 | wall2 = HorizontalWall([Lx1,Lx2],Ly1) 187 | wall3 = HorizontalWall([Lx1,Lx2],Ly2) 188 | rightsharedwall = VerticalSharedWall(Lx2,[Ly1,Ly3,Ly4,Ly2],(nofcell,nofcell+1)) 189 | disk = create_disk(Lx1,Lx2,Ly1,Ly2, radiusdisk, massdisk, velocitydisk, nofcell) 190 | particle = create_particle(Lx1,Lx2,Ly1,Ly2, massparticle, velocityparticle, nofcell) 191 | while overlap(particle,disk) 192 | disk = create_disk(Lx1,Lx2,Ly1,Ly2, radiusdisk, massdisk, velocitydisk, nofcell) 193 | particle = create_particle(Lx1,Lx2,Ly1,Ly2, massparticle, velocityparticle, nofcell) 194 | end 195 | cell = Cell([leftsharedwall,wall2,wall3,rightsharedwall],disk,nofcell) 196 | cell, particle 197 | end 198 | 199 | @doc """#parameters_to_create_a_new_cell(::Cell) 200 | Extract the general data associated to a previous created cell"""-> 201 | function parameters_to_create_a_new_cell(cell::Cell) 202 | size_x = cell.walls[4].x - cell.walls[1].x 203 | size_y = cell.walls[3].y - cell.walls[2].y 204 | radiusdisk = cell.disk.radius 205 | massdisk = cell.disk.mass 206 | velocitydisk = 0. 207 | #velocitydisk = norm(cell.disk.v) ######Ver la forma de mejorar esto 208 | windowsize = cell.walls[1].y[3] - cell.walls[1].y[2] 209 | size_x, size_y, radiusdisk, massdisk, velocitydisk, windowsize 210 | end 211 | 212 | 213 | @doc """#create_new_right_cell(::Cell,::Particle) 214 | Creates a new cell that shares the rightmost verticalwall of the passed cell. A Particle is passed 215 | to avoid overlap with the embedded Disk. 216 | """-> 217 | function create_new_right_cell(cell::Cell, particle::Particle) 218 | size_x, size_y, radiusdisk, massdisk, velocitydisk, windowsize = parameters_to_create_a_new_cell(cell) 219 | 220 | leftsharedwall = cell.walls[end] 221 | Lx1 = cell.walls[end].x 222 | Ly1 = cell.walls[end].y[1] 223 | Lx2 = Lx1 + size_x 224 | Ly2 = Ly1 + size_y 225 | wall2 = HorizontalWall([Lx1,Lx2],Ly1) 226 | wall3 = HorizontalWall([Lx1,Lx2],Ly2) 227 | Ly3, Ly4 = create_window(Ly1, Ly2, windowsize) 228 | nofcell = cell.numberofcell +1 229 | disk = create_disk(Lx1,Lx2,Ly1,Ly2, radiusdisk, massdisk, velocitydisk, nofcell) 230 | while overlap(particle,disk) 231 | disk = create_disk(Lx1,Lx2,Ly1,Ly2, radiusdisk, massdisk, velocitydisk, nofcell) 232 | end 233 | rightsharedwall = VerticalSharedWall(Lx2,[Ly1,Ly3,Ly4,Ly2],(nofcell,nofcell+1)) 234 | cell = Cell([leftsharedwall,wall2,wall3,rightsharedwall],disk,nofcell) 235 | cell 236 | end 237 | 238 | 239 | @doc """#create_new_left_cell(::Cell,::Particle) 240 | Creates a new cell that shares the leftmost verticalwall of the passed cell. A Particle is passed 241 | to avoid overlap with the embedded Disk. 242 | """-> 243 | function create_new_left_cell(cell::Cell, particle::Particle) 244 | size_x, size_y, radiusdisk, massdisk, velocitydisk, windowsize = parameters_to_create_a_new_cell(cell) 245 | 246 | Lx2 = cell.walls[1].x 247 | Ly1 = cell.walls[1].y[1] 248 | Lx1 = Lx2 - size_x 249 | Ly2 = Ly1 + size_y 250 | wall2 = HorizontalWall([Lx1,Lx2],Ly1) 251 | wall3 = HorizontalWall([Lx1,Lx2],Ly2) 252 | rightsharedwall = cell.walls[1] 253 | Ly3, Ly4 = create_window(Ly1, Ly2, windowsize) 254 | nofcell = cell.numberofcell - 1 255 | disk = create_disk(Lx1,Lx2,Ly1,Ly2, radiusdisk, massdisk, velocitydisk,nofcell) 256 | while overlap(particle,disk) 257 | disk = create_disk(Lx1,Lx2,Ly1,Ly2, radiusdisk, massdisk, velocitydisk, nofcell) 258 | end 259 | leftsharedwall = VerticalSharedWall(Lx1,[Ly1,Ly3,Ly4,Ly2],(nofcell,nofcell-1)) 260 | cell = Cell([leftsharedwall,wall2,wall3,rightsharedwall],disk,nofcell) 261 | cell 262 | end 263 | 264 | @doc """#create_board_with_particle(Lx1, Ly1,size_x,size_y,radiusdisk, massdisk, velocitydisk, massparticle, velocityparticle, windowsize) 265 | Returns a Board instance with one cell and a particle inside it (that is also returned). Size of its sides and initial coordinates for the left down corner are passed (Lx1,Ly1) 266 | together with the needed data to create the embedded disk and a particle inside the cell. """-> 267 | function create_board_with_particle(Lx1::Real, Ly1::Real,size_x::Real,size_y::Real,radiusdisk::Real, 268 | massdisk::Real, velocitydisk::Real, 269 | massparticle::Real, velocityparticle::Real, windowsize::Real) 270 | cell, particle = create_initial_cell_with_particle(Lx1, Ly1,size_x,size_y,radiusdisk, massdisk, velocitydisk, 271 | massparticle, velocityparticle, windowsize) 272 | board = Deque{Cell}() 273 | push!(board,cell) 274 | board = Board(board) 275 | board, particle 276 | end 277 | 278 | 279 | @doc """#move(::Disk, dt::Real) 280 | Update the position of the Disk by moving it a time dt"""-> 281 | move(d::Disk, dt::Real) = d.r += d.v * dt 282 | @doc """#move(::Particle, dt::Real) 283 | Update the position of the Particle by moving it a time dt"""-> 284 | move(p::Particle, dt::Real) = p.r += p.v*dt 285 | 286 | ####Time 287 | #######################################Disk#################################################3 288 | 289 | @doc """#dtcollision(::Disk,::Vertical) 290 | Returns the time of collision between a Disk and a Vertical (Wall). If they don't collide it retuns ∞ """-> 291 | function dtcollision(d::Disk, VW::Vertical) 292 | #La pared siempre va a estar acotada por números positivos 293 | dt = Inf 294 | if d.v[1] > 0 295 | if d.r[1] < VW.x 296 | dt = (VW.x - (d.r[1] + d.radius))/d.v[1] 297 | end 298 | elseif d.v[1] < 0 299 | if d.r[1] > VW.x 300 | dt = ((d.r[1] - d.radius) - VW.x)/-d.v[1] 301 | end 302 | end 303 | dt 304 | end 305 | 306 | 307 | @doc """#dtcollision(::Disk,::HorizontalWall) 308 | Returns the time of collision between a Disk and a HorizontallWall.If they don't collide it retuns ∞"""-> 309 | function dtcollision(d::Disk, HW::HorizontalWall) 310 | dt = Inf 311 | if d.v[2] > 0 312 | if d.r[2] < HW.y 313 | dt = (HW.y - (d.r[2] + d.radius))/d.v[2] 314 | end 315 | elseif d.v[2] < 0 316 | if d.r[2] > HW.y 317 | dt = ((d.r[2] - d.radius) - HW.y)/-d.v[2] 318 | end 319 | end 320 | dt 321 | end 322 | 323 | @doc """#dtcollision(::Disk,::Cell) 324 | Calculates the minimum time of collision between the Disk belonged to Cell and the Walls of the Cell. It retuns 325 | the interval of time and the index of the Wall inside the Cell: 326 | > 1 = left wall, 2 = bottom wall, 3 = top wall, 4 = right wall."""-> 327 | function dtcollision(d::Disk, c::Cell) 328 | time = zeros(4) 329 | index = 1 330 | for wall in c.walls 331 | dt = dtcollision(d,wall) 332 | time[index] = dt 333 | index += 1 334 | end 335 | dt,k = findmin(time) 336 | end 337 | 338 | @doc """#dtcollision(::Disk,::Particle) 339 | Calculates the time of collision between a Disk and the Particle in the same cell.If they don't collide it retuns ∞"""-> 340 | function dtcollision(d::Disk, p::Particle) 341 | deltar = p.r - d.r 342 | deltav = p.v - d.v 343 | rdotv = dot(deltar, deltav) 344 | rcuadrado = dot(deltar,deltar) 345 | vcuadrado = dot(deltav, deltav) 346 | if rdotv >= 0 347 | return Inf 348 | end 349 | dis = (rdotv)^2 -(vcuadrado)*(rcuadrado - (d.radius)^2) 350 | if dis < 0 351 | return Inf 352 | end 353 | dt = (rcuadrado - (d.radius)^2)/(-rdotv + sqrt(dis)) 354 | return dt 355 | end 356 | 357 | ################################Particle#############################################################3 358 | 359 | @doc """#dtcollision(::Particle, ::Vertical) 360 | Calculates the time of collision between a Particle and a VerticalWall.If they don't collide it retuns ∞ """-> 361 | function dtcollision(p::Particle, VW::Vertical) 362 | dt = (VW.x - p.r[1])/p.v[1] 363 | if dt < 0 364 | return Inf 365 | end 366 | dt 367 | end 368 | 369 | @doc doc"""#dtcollision(::Particle,::HorizontalWall) 370 | Returns the time of collision between a Disk and a HorizontallWall.If they don't collide it retuns ∞"""-> 371 | function dtcollision(p::Particle, HW::HorizontalWall) 372 | dt = (HW.y - p.r[2])/p.v[2] 373 | if dt < 0 374 | return Inf 375 | end 376 | dt 377 | end 378 | 379 | @doc """#dtcollision(::Particle,::Disk) 380 | See *dtcollision(::Disk,::Particle)*"""-> 381 | dtcollision(p::Particle, d::Disk) = dtcollision(d::Disk, p::Particle) 382 | 383 | @doc """#dtcollision(::Particle,::Cell) 384 | Calculates the minimum time of collision between a Particle and the Walls of the a. It retuns 385 | the interval of time and the index of the Wall inside the Cell: 386 | > 1 = left wall, 2 = bottom wall, 3 = top wall, 4 = right wall."""-> 387 | function dtcollision(p::Particle,c::Cell) 388 | time = zeros(4) 389 | index = 1 390 | for wall in c.walls 391 | dt = dtcollision(p,wall) 392 | time[index] = dt 393 | index += 1 394 | end 395 | dt,k = findmin(time) 396 | end 397 | 398 | ==(w1::Wall,w2::Wall) = (w1.x == w2.x && w1.y == w2.y) 399 | 400 | @doc doc"""#dtcollision(::Particle,::Cell, ::Wall) 401 | This function is similar to *dtcollision(::Particle,::Cell)* but avoids 402 | the recollision between a Particle and a Wall in the next event if they collides in the last Event.""" -> 403 | function dtcollision(p::Particle,c::Cell, w::Wall) 404 | time = zeros(4) 405 | index = 1 406 | for walle in c.walls 407 | if walle == w 408 | dt = Inf 409 | else 410 | dt = dtcollision(p,walle) 411 | end 412 | time[index] = dt 413 | index += 1 414 | end 415 | dt,k = findmin(time) 416 | end 417 | 418 | 419 | 420 | ########################################################################################## 421 | #Rules 422 | ###############Disk################################################## 423 | @doc doc"""#collision(::Disk, ::Vertical, ::Board) 424 | Update the velocity vector of a Disk (Disk.v) after it collides with a Vertical(Wall)."""-> 425 | function collision(d::Disk, V::Vertical) 426 | d.v = [-d.v[1], d.v[2]] 427 | end 428 | 429 | @doc doc"""#collision(::Disk, ::Vertical, ::Board) 430 | Update the velocity vector of a Disk (Disk.v) after it collides with a Vertical(Wall). The Board is given just to 431 | enforce the fact that collision is made in the context of a Cell. """-> 432 | function collision(d::Disk, V::Vertical,b::Board) 433 | collision(d,V) 434 | end 435 | 436 | @doc doc"""#collision(::Disk, ::HorizontalWall, ::Board) 437 | Update the velocity vector of a Disk (Disk.v) after it collides with a HorizontallWall."""-> 438 | function collision(d::Disk, H::HorizontalWall) 439 | d.v = [d.v[1],-d.v[2]] 440 | end 441 | 442 | @doc doc"""#collision(::Disk, ::HorizontalWall, ::Board) 443 | Update the velocity vector of a Disk (Disk.v) after it collides with a HorizontallWall. The Board is given just to 444 | enforce the fact that collision is made in the context of a Cell."""-> 445 | function collision(d::Disk, H::HorizontalWall, b::Board) 446 | collision(d,H) 447 | end 448 | 449 | ###################Particle##############################################33 450 | @doc doc"""#collision(::Particle, ::HorizontalWall) 451 | Update the velocity vector of a Particle (Particle.v) after it collides with a HorizontallWall."""-> 452 | function collision(p::Particle, H::HorizontalWall) 453 | p.v = [p.v[1],-p.v[2]] 454 | end 455 | 456 | @doc doc"""#collision(::Particle, ::HorizontalWall, ::Board) 457 | Update the velocity vector of a Particle (Particle.v) after it collides with a HorizontallWall. The Board is given just to 458 | enforce the fact that collision is made in the context of a Cell."""-> 459 | function collision(p::Particle, H::HorizontalWall, b::Board ) 460 | collision(p,H) 461 | end 462 | 463 | @doc """#collision(::Particle, ::Vertical) 464 | Update the velocity vector of a Particle (Particle.v) after it collides with a rigid Vertical(Wall)."""-> 465 | function collision(p::Particle, VW::Vertical) 466 | p.v = [-p.v[1], p.v[2]] 467 | end 468 | 469 | 470 | @doc """#collision(::Particle, ::VerticalSharedWall, ::Board) 471 | Update the attributes of the particle according to the site where it collides with the VerticalSharedWall. If the collision is 472 | through the window, the label of the particle is updated to the label of the new cell, that is created in case it wasn't 473 | done before. Else if the collision is through the rigid part of the wall, it updates the particle velocity according to a 474 | specular collision"""-> 475 | function collision(p::Particle, VSW::VerticalSharedWall, b::Board) 476 | new = false 477 | if updateparticlelabel(p,VSW) 478 | if !is_cell_in_board(b, p) 479 | newcell!(b,p) 480 | new = true 481 | end 482 | else 483 | collision(p,VSW) 484 | end 485 | new 486 | end 487 | 488 | @doc """#updateparticlelabel(::Particle, ::VerticalSharedWall) 489 | Update the label of the particle when it passes through the window of the VerticalSharedWall."""-> 490 | function updateparticlelabel(p::Particle, VSW::VerticalSharedWall) 491 | update = false 492 | Ly1window = VSW.y[2] 493 | Ly2window= VSW.y[3] 494 | if Ly1window < p.r[2] < Ly2window 495 | pcell = p.numberofcell 496 | for nofcell in VSW.sharedcells 497 | if pcell != nofcell 498 | p.numberofcell = nofcell 499 | end 500 | end 501 | update = true 502 | end 503 | update 504 | end 505 | 506 | 507 | @doc """#is_cell_in_board(::Board,::Particle) 508 | Ask for the existence of a Cell with the label associated to the Particle (Particle.numberofcell)"""-> 509 | function is_cell_in_board(b::Board,p::Particle) 510 | iscell = false 511 | if back(b.cells).numberofcell <= p.numberofcell <= front(b.cells).numberofcell 512 | iscell = true 513 | end 514 | iscell 515 | end 516 | 517 | @doc """#newcell!(::Board, ::Particle) 518 | Integerroduces a new cell on the board according to the value of the attribute *numberofcell* of the particle. 519 | It may pushes the cell at the left or right side of the board to mantain the order in the **Deque** structure of the 520 | board: at the back the leftmost cell, at front the rightmost cell."""-> 521 | function newcell!(b::Board, p::Particle) 522 | if back(b.cells).numberofcell - 1 == p.numberofcell 523 | cell = create_new_left_cell(back(b.cells),p) 524 | push!(b.cells, cell) 525 | elseif front(b.cells).numberofcell + 1 == p.numberofcell 526 | cell = create_new_right_cell(front(b.cells),p) 527 | unshift!(b.cells,cell) 528 | end 529 | end 530 | 531 | @doc """#collision(::Particle, ::Disk) 532 | Updates the velocities for the Particle and Disk after they collides through an elastic collision. """-> 533 | function collision(p::Particle, d::Disk) 534 | deltar = p.r - d.r 535 | deltav = p.v - d.v 536 | h = dot(deltar,deltav) 537 | sigma = d.radius 538 | J = 2*p.mass*d.mass*h/(sigma*(p.mass + d.mass)) 539 | p.v -= J*deltar/(sigma*p.mass) 540 | d.v += J*deltar/(sigma*d.mass) 541 | end 542 | 543 | @doc """#collision(::Particle, ::Disk, ::Board) 544 | Updates the velocities for the Particle and Disk after they collides through an elastic collision. The Board is given just to 545 | enforce the fact that collision is made in the context of a Cell. """-> 546 | function collision(p::Particle, d::Disk, b::Board) 547 | collision(p,d) 548 | end 549 | 550 | 551 | @doc """#collision(::Disk, ::Particle) 552 | See *collision(::Particle, ::Disk)*"""-> 553 | collision(d::Disk, p::Particle) = collision(p::Particle, d::Disk) 554 | 555 | @doc """#collision(::Disk, ::Particle, ::Board). 556 | See *collision(::Particle, ::Disk, ::Board)*"""-> 557 | collision(d::Disk, p::Particle, b::Board) = collision(p::Particle, d::Disk, b::Board) 558 | 559 | end 560 | --------------------------------------------------------------------------------