From df1fa2433f58fb1b9542ad9b36beacc52389ff7f Mon Sep 17 00:00:00 2001 From: tomprotin Date: Fri, 16 Feb 2024 16:50:23 +0100 Subject: [PATCH 01/37] small changes to make PiCLES work on my local --- .gitignore | 2 ++ src/PiCLES.jl | 6 +++--- tests/T04_2D_box_rotation.jl | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index d189a7a..5715b2b 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ config/config.json plots/* .DS_Store + +.ipynb* diff --git a/src/PiCLES.jl b/src/PiCLES.jl index 387d60f..a828922 100644 --- a/src/PiCLES.jl +++ b/src/PiCLES.jl @@ -26,7 +26,7 @@ export ParticleMesh, # utils - Utils, Debugging, FetchRelations, ParticleTools, WindEmulator + Utils, Debugging, FetchRelations, ParticleTools, WindEmulator, visualization #externals @@ -65,7 +65,7 @@ using .Simulations include("Models/Models.jl") using .Models -# include("visualization/Plotting.jl") -# using .Plotting +include("visualization/Plotting.jl") +using .Plotting end \ No newline at end of file diff --git a/tests/T04_2D_box_rotation.jl b/tests/T04_2D_box_rotation.jl index 41a76f8..2c4df66 100644 --- a/tests/T04_2D_box_rotation.jl +++ b/tests/T04_2D_box_rotation.jl @@ -22,10 +22,12 @@ import Oceananigans.Utils: prettytime using PiCLES.Architectures using GLMakie - +using Revise using PiCLES.Operators.core_2D: GetGroupVelocity, speed using PiCLES.Plotting.movie: init_movie_2D_box_plot +using Revise + # debugging: #using ProfileView From 713c64a9c512c7dcccc729e015a29d6304294817 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Fri, 16 Feb 2024 18:04:55 +0100 Subject: [PATCH 02/37] created new model for geometrical optics management, lots of changes comming... --- src/Models/GeometricalOpticsModels.jl | 288 ++++++++++++++++++++++++++ src/Models/Models.jl | 4 +- 2 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 src/Models/GeometricalOpticsModels.jl diff --git a/src/Models/GeometricalOpticsModels.jl b/src/Models/GeometricalOpticsModels.jl new file mode 100644 index 0000000..bd83896 --- /dev/null +++ b/src/Models/GeometricalOpticsModels.jl @@ -0,0 +1,288 @@ +module GeometricalOpticsModels + +export WaveGrowth2D, init_particles! +export fields + +using ...Architectures + +using ModelingToolkit: get_states, ODESystem + +#using core_1D: MarkedParticleInstance +using ...ParticleMesh: OneDGrid, OneDGridNotes, TwoDGrid, TwoDGridNotes + +using ...Operators.core_2D: ParticleDefaults as ParticleDefaults2D +#using core_2D: SeedParticle! as SeedParticle2D! +using ...Operators.mapping_2D + +using SharedArrays +# using DistributedArrays +using Printf + +import Oceananigans: fields +using Oceananigans.TimeSteppers: Clock +using ...FetchRelations + +#includet("mapping_1D.jl") + +# TO DO : check if all the modules imported above are necessary, for now I just copied the ones from WaveGrowthModels2D.jl + + + +""" + GeometricalOptics{Grid, Lay, Tim, Clo, stat, PC, Ovar, Osys, Oses, Odev, bl_flag, bl, wnds, cur} + + ADD HERE A DESCRIPTION OF THE MODEL + +""" +mutable struct GeometricalOptics{Grid<:AbstractGrid, + Lay, + Tim, + Clo, + Int, + stat, + PCollection, + FPC, + Ovar, + Osys, + Oses, + Odev, + MinPar, + MinStat, + bl_flag, + bl, + bl_type, + wnds, + cur, + Mstat} <: Abstract2DModel where {Mstat<:Union{Nothing,stat}, PCollection<:Union{Vector,Array}} + #Union{Vector,DArray} + grid::Grid + layers::Lay # number of layers used in the model, 1 is eneough + timestepper::Tim # silly Oceananigans + clock::Clo + dims::Int # number of dimensions + + State::stat # state of of the model at each grid point, for each layer it contains, energy, positions, group speed + ParticleCollection::PCollection # Collection (list) of Particles + FailedCollection::FPC # Collection (list) of Particles that failed to integrate + + ODEvars::Ovar # list of variables in ODE system, have type Num from OrdinaryDiffEq and ModelingToolkit + ODEsystem::Osys # the ODE system used at each particle + ODEsettings::Oses # All setting needed to solve the ODEsystem + ODEdefaults::Odev # Dict{NUm, Float64} ODE defaults + minimal_particle::MinPar + minimal_state::MinStat + + periodic_boundary::bl_flag # If true we use a period boundary + boundary::bl # List of boundary points + boundary_defaults::bl_type # Dict{NUm, Float64} ODE defaults + + winds::wnds # u, v, if needed u_x, u_y + currents::cur # u, v, currents + + MovieState::Mstat # state of of the model. Only used for producing movieframes + +end + + + + +## 2D version +""" +mark_boundary(grid::TwoDGrid) +function that returns list of boundary nodes (tuples of indixes) +""" +function mark_boundary(grid::TwoDGrid) + #get x and y coordinates + xi = collect(range(1, stop=grid.Nx, step=1)) + yi = collect(range(1, stop=grid.Ny, step=1)) + + # make boundary nodes + a = [(xi[i], yi[j]) for j in 1:grid.Ny , i in [1, grid.Nx]] + b = [(xi[i], yi[j]) for j in [1, grid.Ny], i in 1:grid.Nx ] + #merge a and b + return vcat(vec(a), vec(b)) #vec(vcat(a, b)) +end + + +""" +WaveGrowth2D(; grid, winds, ODEsys, ODEvars, layers, clock, ODEsets, ODEdefaults, currents, periodic_boundary, CBsets) +This is the constructor for the WaveGrowth2D model. The inputs are: + grid : the grid used in the model, + winds : the wind interpolation function here only 1D, + ODEsys : the ODE system used in the model, + ODEvars : the variables in the ODE system, + layers : the number of layers used in the model (default 1), + clock : the clock used in the model, + ODEsets : the ODE settings (type: ODESettings), + ODEdefaults : the ODE defaults (type: ParticleDefaults), + currents : the currents (not implimented yet), + periodic_boundary: if true we use a periodic boundary (default true), + CBsets : the callback settings (not implimented yet). +""" +function WaveGrowth2D(; grid::TwoDGrid, + winds::NamedTuple{(:u, :v)}, + ODEsys, + ODEvars=nothing, #needed for MTK for ODEsystem. will be depriciated later + layers::Int=1, + clock=Clock{eltype(grid)}(0, 0, 1), + ODEsets::AbstractODESettings=nothing, # ODE_settings + ODEinit_type::PP= "wind_sea", # default_ODE_parameters + minimal_particle=nothing, # minimum particle the model falls back to if a particle fails to integrate + minimal_state=nothing, # minimum state threshold needed for the state to be advanced + currents=nothing, # + periodic_boundary=true, + boundary_type="same", # or "minimal", "same", default is same, only used if periodic_boundary is false + CBsets=nothing, + movie=false) where {PP<:Union{ParticleDefaults2D,String}} + + # initialize state {SharedArray} given grid and layers + # Number of state variables + Nstate = 3 + if layers > 1 + State = SharedArray{Float64,4}(grid.Nx, grid.Ny, Nstate, layers) + else + State = SharedArray{Float64,3}(grid.Nx, grid.Ny, Nstate) + end + + if ODEinit_type isa ParticleDefaults2D + ODEdefaults = ODEinit_type + elseif ODEinit_type == "wind_sea" + ODEdefaults = nothing + elseif ODEinit_type == "mininmal" + ODEdefaults = ParticleDefaults1D(-11.0, 1e-3, 0.0) + else + error("ODEinit_type must be either 'wind_sea','mininmal', or ParticleDefaults2D instance ") + end + + if isnothing(minimal_particle) + @info "initalize minimum particle" + minimal_particle = FetchRelations.MinimalParticle(2, 2, ODEsets.timestep) + else + @info "use minimal particle" + end + + if isnothing(minimal_state) + @info "initalize minimum state" + minimal_state = FetchRelations.MinimalState(2, 2, ODEsets.timestep) + else + @info "use minimal state" + end + + # initliaze boundary points (periodic_boundary) + if ~periodic_boundary # if false, define boundary points here: + boundary = boundary = mark_boundary(grid) + else + boundary = [] + end + + if boundary_type == "wind_sea" + boundary_defaults = nothing + @info "use wind_sea boundary" + elseif boundary_type == "mininmal" + @info "use 'mininmal' boundary (1min with 2m/s)" + #FetchRelations.get_minimal_windsea(u(0, 0), ODEsets.DT) + WindSeamin = FetchRelations.get_minimal_windsea(1, 1, 5*60) # 5 min with 2 m/s + #WindSeamin = FetchRelations.get_minimal_windsea(u(0, 0, 0), v(0, 0, 0), DT / 2) + #WindSeamin = FetchRelations.get_initial_windsea(u(0, 0, 0), v(0, 0, 0), DT/5) + lne_local = log(WindSeamin["E"]) + cg_u_local = WindSeamin["cg_bar_x"] + cg_v_local = WindSeamin["cg_bar_y"] + boundary_defaults = copy(ParticleDefaults2D(lne_local, cg_u_local, cg_v_local, 0.0, 0.0)) + + elseif boundary_type == "same" + @info "use default value boundary" + boundary_defaults = ODEdefaults + else + error("boundary_type must be either 'wind_sea','mininmal', or 'same' ") + end + + ParticleCollection = [] + FailedCollection = Vector{AbstractMarkedParticleInstance}([]) + # particle initialization is not done in the init_particle! method + # for i in range(1,length = grid.Nx) + # SeedParticle!(ParticleCollection, State, i, + # ODEsys, ODEdev, ODEsets, + # gridnotes, winds, ODEsets.timestep, grid.Nx, boundary, periodic_boundary) + # end + + # check dimensions of all components: + # check Nstate ODEvars + if movie + Mstat = State + else + Mstat = nothing + end + + # return WaveGrowth2D structure + return WaveGrowth2D( + grid, + layers, + nothing, + clock, # ??? + 2, # This is a 2D model + State, + ParticleCollection, + FailedCollection, + ODEvars, + ODEsys, + ODEsets, + ODEdefaults, + minimal_particle, + minimal_state, + periodic_boundary, + boundary, boundary_defaults, + winds, + currents, + Mstat) +end + + + + +""" + fields(model::WaveGrowth) + +Return a flattened `NamedTuple` of the State vector for a `WaveGrowth2D` model. +""" +fields(model::WaveGrowth2D) = (State=model.State,) +# # Oceananigans.Simulations interface +# fields(m::ContinuumIceModel) = merge(m.velocities, m.stresses) + +function reset_boundary!(model::WaveGrowth2D) + + if model.periodic_boundary # if false, define boundary points here: + boundary = [] + else + boundary = boundary = mark_boundary(grid) + end + +end + + +function Base.show(io::IO, ow::WaveGrowth2D) + + if ow.ODEsystem isa ODESystem + sys_print = get_states(ow.ODEsystem) + else + sys_print = ow.ODEsystem + end + print(io, "WaveGrowth2D ", "\n", + "├── grid: ", ow.grid, "\n", + "├── layers: ", ow.layers, "\n", + "├── clock: ", ow.clock, + "├── State: ", size(ow.State), "\n", + "├── ParticleCollection size: ", length(ow.ParticleCollection), "\n", + "├── ODEs \n", + "| ├── System: ", sys_print, "\n", + "| ├── Defaults: ", ow.ODEdefaults, "\n", + "| └── Settings: \n", ow.ODEsettings, "\n", + "├── winds ", ow.winds, "\n", + "├── currents ", ow.currents, "\n", + "└── Perdiodic Boundary ", ow.periodic_boundary, "\n") +end + + + + +# end of module +end \ No newline at end of file diff --git a/src/Models/Models.jl b/src/Models/Models.jl index daa8a40..7459798 100644 --- a/src/Models/Models.jl +++ b/src/Models/Models.jl @@ -1,11 +1,13 @@ module Models -export WaveGrowthModels1D, WaveGrowthModels2D, reset_boundary! +export WaveGrowthModels1D, WaveGrowthModels2D, GeometricalOpticsModels, reset_boundary! include("WaveGrowthModels1D.jl") include("WaveGrowthModels2D.jl") +include("GeometricalOpticsModels.jl") using .WaveGrowthModels1D using .WaveGrowthModels2D +using .GeometricalOpticsModels end \ No newline at end of file From e601668f1cf046892dafcffc97560e45d6bb20d8 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Wed, 28 Feb 2024 09:56:01 +0100 Subject: [PATCH 03/37] Changed every occurence of WaveGrowth2D to GeometricalOptics --- src/Models/GeometricalOpticsModels.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Models/GeometricalOpticsModels.jl b/src/Models/GeometricalOpticsModels.jl index bd83896..4a766b7 100644 --- a/src/Models/GeometricalOpticsModels.jl +++ b/src/Models/GeometricalOpticsModels.jl @@ -1,6 +1,6 @@ module GeometricalOpticsModels -export WaveGrowth2D, init_particles! +export GeometricalOptics, init_particles! export fields using ...Architectures @@ -119,7 +119,7 @@ This is the constructor for the WaveGrowth2D model. The inputs are: periodic_boundary: if true we use a periodic boundary (default true), CBsets : the callback settings (not implimented yet). """ -function WaveGrowth2D(; grid::TwoDGrid, +function GeometricalOptics(; grid::TwoDGrid, winds::NamedTuple{(:u, :v)}, ODEsys, ODEvars=nothing, #needed for MTK for ODEsystem. will be depriciated later @@ -214,7 +214,7 @@ function WaveGrowth2D(; grid::TwoDGrid, end # return WaveGrowth2D structure - return WaveGrowth2D( + return GeometricalOptics( grid, layers, nothing, @@ -242,13 +242,13 @@ end """ fields(model::WaveGrowth) -Return a flattened `NamedTuple` of the State vector for a `WaveGrowth2D` model. +Return a flattened `NamedTuple` of the State vector for a `GeometricalOptics` model. """ -fields(model::WaveGrowth2D) = (State=model.State,) +fields(model::GeometricalOptics) = (State=model.State,) # # Oceananigans.Simulations interface # fields(m::ContinuumIceModel) = merge(m.velocities, m.stresses) -function reset_boundary!(model::WaveGrowth2D) +function reset_boundary!(model::GeometricalOptics) if model.periodic_boundary # if false, define boundary points here: boundary = [] @@ -259,14 +259,14 @@ function reset_boundary!(model::WaveGrowth2D) end -function Base.show(io::IO, ow::WaveGrowth2D) +function Base.show(io::IO, ow::GeometricalOptics) if ow.ODEsystem isa ODESystem sys_print = get_states(ow.ODEsystem) else sys_print = ow.ODEsystem end - print(io, "WaveGrowth2D ", "\n", + print(io, "GeometricalOptics ", "\n", "├── grid: ", ow.grid, "\n", "├── layers: ", ow.layers, "\n", "├── clock: ", ow.clock, From b7ab9cb084b64f3fe5845ef6e4f7568e2eeaff00 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Wed, 28 Feb 2024 09:56:35 +0100 Subject: [PATCH 04/37] Added new particle system copied from particle_waves_v5 --- src/ParticleSystems/ParticleSystems.jl | 4 +- src/ParticleSystems/particle_waves_v6.jl | 597 +++++++++++++++++++++++ 2 files changed, 600 insertions(+), 1 deletion(-) create mode 100644 src/ParticleSystems/particle_waves_v6.jl diff --git a/src/ParticleSystems/ParticleSystems.jl b/src/ParticleSystems/ParticleSystems.jl index 50aa90e..9d4bdb2 100644 --- a/src/ParticleSystems/ParticleSystems.jl +++ b/src/ParticleSystems/ParticleSystems.jl @@ -1,16 +1,18 @@ module ParticleSystems -export particle_waves_v3, particle_waves_v3beta, particle_waves_v4, particle_waves_v5 +export particle_waves_v3, particle_waves_v3beta, particle_waves_v4, particle_waves_v5, particle_waves_v5 include("particle_waves_v3beta.jl") include("particle_waves_v3.jl") include("particle_waves_v4.jl") include("particle_waves_v5.jl") +include("particle_waves_v6.jl") using .particle_waves_v3beta using .particle_waves_v3 using .particle_waves_v4 using .particle_waves_v5 +using .particle_waves_v6 end \ No newline at end of file diff --git a/src/ParticleSystems/particle_waves_v6.jl b/src/ParticleSystems/particle_waves_v6.jl new file mode 100644 index 0000000..caa5a5d --- /dev/null +++ b/src/ParticleSystems/particle_waves_v6.jl @@ -0,0 +1,597 @@ +module particle_waves_v6 + +using DifferentialEquations, IfElse + +using ...Architectures: AbstractODESettings, AbstractParticleSystem + +export particle_equations, ODESettings +using LinearAlgebra +using StaticArrays + +using Parameters +using DocStringExtensions +#export t, x, y, e, c̄, φ_p, dist, Gₙ, u_10 + +# #using Plots +# #using PyPlot +# +# using PyCall +# #pygui(gui) #:tk, :gtk3, :gtk, :qt5, :qt4, :qt, or :wx +# using PyPlot + +# startupfile = joinpath(pwd(), "2022_particle_waves_startup.jl") +# isfile(startupfile) && include(startupfile) + +###### + + +""" +ODESettings +Structure to hold all information about the ODE system +# Fields +$(DocStringExtensions.FIELDS) +""" +@with_kw struct ODESettings <: AbstractODESettings + "ODE parameters (Dict)" + Parameters::NamedTuple + "minimum allowed log energy on particle " + log_energy_minimum::Float64 + "maximum allowed log energy on particle " + log_energy_maximum::Float64 = log(17) + + "minimum needed squared wind velocity to seed particle" + wind_min_squared::Float64 = 4.0 + "solver method for ODE system" + #alternatives + #Rosenbrock23(), AutoVern7(Rodas4()) ,AutoTsit5(Rosenbrock23()) , Tsit5() + solver::Any = AutoTsit5(Rosenbrock23()) + "Internal saving timestep of the ODEs" + saving_step::Float64 + "remeshing time step, i.e. timestep of the model" + timestep::Float64 + + "Absolute allowed error" + abstol::Float64 = 1e-4 + "relative allowed error" + reltol::Float64 = 1e-3 + "max iteration for ODE solver (1e4)" + maxiters::Int = 1e4 + "Adaptive timestepping for ODE (true)" + adaptive::Bool = true + "timestep (if adaptive is false this is used), if adaptive is true this is the initial timestep" + dt::Float64 = 60 * 6 # seconds + "min timestep (if adaptive is true)" + dtmin::Float64 = 60 * 5 # seconds + "force min timestep (if adaptive is true)" + force_dtmin::Bool = false + + "Total time of the ODE integration, should not be needed, this is problematic .. " + total_time::Float64 + + "Callback function for ODE solver" + callbacks::Any = nothing + "save_everystep (false)" + save_everystep::Bool = false +end + + +# function init_vars() +# @variables t +# @variables x(t), y(t), c̄_x(t), c̄_y(t), lne(t), Δn(t), Δφ_p(t) +# @parameters r_g C_α C_φ g C_e +# return t, x, y, c̄_x, c̄_y, lne, Δn, Δφ_p, r_g, C_α, C_φ, g, C_e +# end + +# function init_vars_1D() +# @variables t +# @variables x(t), c̄_x(t), lne(t) +# @parameters r_g C_α g C_e +# return t, x, c̄_x, lne, r_g, C_α, g, C_e +# end + +# ------------------------------------------------------ +# Paramter functions +# ------------------------------------------------------ + +function magic_fractions(q::Float64=-1 / 4.0) + # returns universal exponent relations + p = (-1 - 10 * q) / 2 + n = 2 * q / (p + 4 * q) + [p, q, n] +end + +""" +get_I_D_constant(; c_D=2e-3, c_β=4e-2, c_e=1.3e-6, c_alpha= 11.8 , r_w = 2.35, q=-1/4) +this function returns a named tuple with the constants for the growth and dissipation +inputs: + c_D: drag coefficient + c_β: + c_e: + c_alpha: + r_w: + q: +returns: + c_D, c_β, c_e, c_alpha, r_w, C_e, γ, p, q, n +""" +function get_I_D_constant(; c_D=2e-3, c_β=4e-2, c_e=1.3e-6, c_alpha=11.8, r_w=2.35, q=-1 / 4) + p = (-1 - 10 * q) / 2 + n = 2 * q / (p + 4 * q) + + C_e = r_w * c_β * c_D + γ = (p - q) * c_alpha^(-4) * C_e^(-1) / 2 + return (c_D=c_D, c_β=c_β, c_e=c_e, c_alpha=c_alpha, r_w=r_w, C_e=C_e, γ=γ, p=p, q=q, n=n) +end + +""" +get_Scg_constants(C_alpha=1.41, C_varphi =1.81e-5) +this function returns a NamedTuple with constants for peak frequency shift. + C_alpha: 1.41 # constant for peak frequency shift (?) + C_varphi: 1.81e-5 # constant for peak frequency shift (?) +""" +function get_Scg_constants(; C_alpha=-1.41, C_varphi=1.81e-5) + return (C_alpha=C_alpha, C_varphi=C_varphi) +end + + + +# # test values +# u = (u=1, v=-1) +# cx = 1.0 +# cy = 1.0 + + + + +""" + αₚ(α::Number, φ::Number, φ_w::Number) + αₚ(α::Number, cφ_p::Number, sφ_p::Number, cφ_w::Number, sφ_w::Number) + αₚ(u::NamedTuple, cg::NamedTuple) + αₚ(u::NamedTuple, cx::Number, cy::Number ) + + returns angle between wave propagation direction and particle orientation. + cg, cx, and cy are the peak wave directions (!), not the mean wave direction! +""" +# αₚ(α::Number, φ::Number, φ_w::Number) = cos.(φ .- φ_w) .* α +#αₚ(α::Number, cφ_p::Number, sφ_p::Number, cφ_w::Number, sφ_w::Number) = (cφ_p .* cφ_w + sφ_p .* sφ_w) .* α +αₚ(u::NamedTuple, cg::NamedTuple) = αₚ(u.u, u.v, cg.cx, cg.cy) +αₚ(u::NamedTuple, cx::Number, cy::Number) = αₚ(u.u, u.v, cx, cy) +αₚ(u::Number, v::Number, cx::Number, cy::Number) = @. (u .* cx + v .* cy) ./ (2 .* max(speed(cx, cy), 1e-4)^2) + +#α_func(u_speed::Number, c_gp_speed::Number) = @. min( u_speed / (2.0 * c_gp_speed), 500) +function α_func(u_speed::Float64, c_gp_speed::Float64) + a = @. u_speed / (2.0 * c_gp_speed) + return IfElse.ifelse( a > 500, 500, a) + #return IfElse.ifelse(u_speed / (2.0 * c_gp_speed) > 500, 500, u_speed / (2.0 * c_gp_speed)) + # if u_speed / (2.0 * c_gp_speed) > 500 + # return 500.0 + # else + # return u_speed / (2.0 * c_gp_speed) + # end + # return min(u_speed / (2.0 * c_gp_speed), 500)::Float64 +end + +function α_func(u_speed, c_gp_speed) + a = @. u_speed / (2.0 * c_gp_speed) + return IfElse.ifelse(a > 500, 500, a) + #return IfElse.ifelse(u_speed / (2.0 * c_gp_speed) > 500, 500, u_speed / (2.0 * c_gp_speed)) + # if u_speed / (2.0 * c_gp_speed) > 500 + # return 500.0 + # else + # return u_speed / (2.0 * c_gp_speed) + # end + # return min(u_speed / (2.0 * c_gp_speed), 500)::Float64 +end + +#sin2_a_min_b(ca::Number, sa::Number, cb::Number, sb::Number) = 4 * sb * cb * (sa^2 -0.5) - 4 * sa * ca * (sb^2 -0.5) +# sign(cx) * +#sin2_a_min_b(ux::Number, uy::Number, cx::Number, cy::Number) = @. (2 / (speed(ux, uy) * speed(cx, cy))^2) * (ux * uy * (2 * cy^2 - speed(cx, cy)^2) - cx * cy * (2 * uy^2 - speed(ux, uy)^2)) +function sin2_a_min_b(ux::Number, uy::Number, cx::Number, cy::Number) + + IfElse.ifelse( + (speed(ux, uy) * speed(cx, cy)) == 0, + 0, + @. (2 / (speed(ux, uy) * speed(cx, cy))^2) * (ux * uy * (2 * cy^2 - speed(cx, cy)^2) - cx * cy * (2 * uy^2 - speed(ux, uy)^2)) + ) +end + +function sin2_a_min_b(u::NamedTuple, cx::Number, cy::Number) + sin2_a_min_b(u.u, u.v, cx, cy) +end +function sin2_a_min_b(u::NamedTuple, c::NamedTuple) + sin2_a_min_b(u.u, u.v, c.cx, c.cy) +end + +sin2_a_plus_b(ux::Number, uy::Number, cx::Number, cy::Number) = (2 / (speed(ux, uy) * speed(cx, cy))^2) * (cx * uy + cy * ux) * (cx * ux - cy * uy) +function sin2_a_plus_b(u::NamedTuple, cx::Number, cy::Number) + sin2_a_plus_b(u.u, u.v, cx, cy) +end +function sin2_a_plus_b(u::NamedTuple, c::NamedTuple) + sin2_a_plus_b(u.u, u.v, c.cx, c.cy) +end + + +#cos2_a_min_b(ca::Number, sa::Number, cb::Number, sb::Number) = (1 - 2 .* (sa .* cb - ca .* cb).^2 ) +e_T_func(γ::Float64, p::Float64, q::Float64, n::Float64; C_e::Number=2.16e-4, c_e::Float64=1.3e-6, c_α::Float64=11.8) = sqrt(c_e * c_α^(-p / q) / (γ * C_e)^(1 / n)) + + +H_β(α::Number, p::Float64; α_thresh::Float64=0.85) = @. 0.5 .* (1.0 + tanh.(p .* (α .- α_thresh))) # <--------------- tanh is slow +Δ_β(α::Number; α_thresh::Float64=0.85) = @. (1.0 .- 1.25 .* sech.(10.0 .* (α .- α_thresh)) .^ 2) + +""" +function c_g_conversions_vector(c̄::Number; g::Number=9.81, r_g::Number=0.9) +returns a vecotr with conversions between c̄, c_gp, kₚ, and ωₚ +""" +function c_g_conversions_vector(c̄::Number; g::Number=9.81, r_g::Number=0.9) # this is a slow function + c_gp = c_g_conversions(c̄, r_g=r_g) + kₚ = g / (4.0 * max(c_gp^2, 1e-2)) # < ---------- the power is slow + ωₚ = g / (2.0 * max(abs(c_gp), 0.1)) + #@SVector [c_gp, kₚ, ωₚ] + c_gp, kₚ, ωₚ +end + +function c_g_conversions(c̄::Float64; r_g::Number=0.9) # this is a slow function + c̄ / r_g +end + +function c_g_conversions(c̄; r_g::Number=0.9) # this is a slow function + c̄ / r_g +end + +speed(cx::Number, cy::Number) = @. sqrt(cx^2 + cy^2) + +function speed_and_angles(cx::Number, cy::Number) + #sqrt(cx.^2 + cy.^2), cx ./ sqrt(cx.^2 + cy.^2), cy ./sqrt(cx.^2 + cy.^2) + c = sqrt.(cx .^ 2 .+ cy .^ 2) + c, cx ./ c, cy ./ c +end + +function speed_and_angles(cx, cy) + #sqrt(cx.^2 + cy.^2), cx ./ sqrt(cx.^2 + cy.^2), cy ./sqrt(cx.^2 + cy.^2) + c = sqrt.(cx .^ 2 .+ cy .^ 2) + c, cx ./ c, cy ./ c +end + + +# ------------------------------- +# Forcing functions +# ------------------------------- + +# wind input +function Ĩ_func(alpha::Number, Hₚ::Number, C_e::Number) + # non-dimensional Wind energy input + # eq sec. 1.3 in the manual + C_e * Hₚ * alpha^2 +end + +# Dissipation +function D̃_func_e(e::Number, kₚ::Number, e_T::Number, n::Float64) + # non-dimensional Wind energy input + # eq sec. 1.3 in the manual + e .^ n .* (kₚ ./ e_T) .^ (2 * n) +end + +# disspation lne version +function D̃_func_lne(lne::Number, kₚ::Number, e_T::Number, n::Float64) + # non-dimensional Wind energy input + # eq sec. 1.3 in the manual + exp(n .* lne) .* (kₚ ./ e_T) .^ (2 * n) +end + + +# peak downshift +# C_α is negative in Kudravtec definition, here its a positive value +S_cg(lne::Number, Δₚ::Number, kₚ::Number, C_α::Number) = @. C_α * Δₚ * kₚ^4 * exp(2 * lne) + + +# Peak direction shift +function S_dir(u::Number, v::Number, cx::Number, cy::Number, C_φ::Number, Hₚ::Number) + return α_func(speed(u, v), speed(cx, cy))^2 * C_φ * Hₚ * sin2_a_min_b(u, v, cx, cy)#::Number + #alpha^2 * C_φ * Hₚ * sin2_a_min_b(cx, cy, u.u, u.v) + + #alpha^2 * C_φ * sin2_a_min_b(u, cx, cy) + #alpha^2 * C_φ * Hₚ * sin2_a_plus_b(u, cx, cy) +end + + +# function Gₙ( dphi_p::Number, dn::Number, dn_0::Number; dg_ratio::Float64 = 0.21 ) +# return (dphi_p / dn_0) * ( (dn /dn_0) / ( (dn/dn_0)^2 + (dg_ratio/2.0)^2 ) ) +# end + + +# tΔφ_w_func(c_x::Number, c_y::Number, u_x::Number, v_y::Number) = (c_x .* v_y - c_y .* u_x ) / ( c_x .* u_x + c_y .* v_y ) +# Δφ_p_RHS(tΔφ_w::Number, tΔφ_p::Number , T_inv::Number) = ( tΔφ_w - tΔφ_p ) * T_inv / ( 1 + tΔφ_w * tΔφ_p ) + + +""" +particle_equations(u , v ; γ::Number=0.88, q::Number=-1/4.0 ) +Particle wave equations in 2D +inputs: + u: zonal wind forcing field + v: meridional wind forcing field + γ: 0.88 + q: -1/4.0 + propagation: true + input: true + dissipation: true + peak_shift: true + direction: true + debug_output: false + +return an ODE system as function particle_system(dz, z, params, t) that provides 5 element state vector tendency of: + z = [lne, c̄_x, c̄_y, x, y] + params can be a named tuple with the parameters or a vector + params = [r_g, C_α, g, C_e] +""" +function particle_equations(u_wind, v_wind; γ::Number=0.88, q::Number=-1 / 4.0, + propagation=true, + input=true, + dissipation=true, + peak_shift=true, + direction=true, + debug_output=false, + static= false + ) + #t, x, y, c̄_x, c̄_y, lne, Δn, Δφ_p, r_g, C_α, C_φ, g, C_e = init_vars() + + p, q, n = magic_fractions(q) + e_T = e_T_func(γ, p, q, n)#, C_e=C_e) + + if static + + function particle_system_static(z, params, t) + + + # forcing fields + #lne, c̄_x, c̄_y, x, y = z + + r_g, C_α, g, C_e, C_φ = params.r_g, params.C_α, params.g, params.C_e, params.C_φ + #u = (u=u, v=v)::NamedTuple{(:u, :v),Tuple{Number,Number}} + u = u_wind(z[4], z[5], t)#::Number + v = v_wind(z[4], z[5], t)#::Number + + c̄ = speed(z[2], z[3]) + u_speed = speed(u, v) + + # peak parameters + c_gp_speed, kₚ, ωₚ = c_g_conversions_vector(abs(c̄), r_g=r_g) + c_gp_x = c_g_conversions(z[2], r_g=r_g) + c_gp_y = c_g_conversions(z[3], r_g=r_g) + + # direction equations + α = α_func(u_speed, c_gp_speed) + Hₚ = H_β(αₚ(u, v, c_gp_x, c_gp_y), p) + Δₚ = Δ_β(αₚ(u, v, c_gp_x, c_gp_y)) + + # Source terms + Ĩ = input ? Ĩ_func(α, Hₚ, C_e) : 0.0 + D̃ = dissipation ? D̃_func_lne(z[1], kₚ, e_T, n) : 0.0 + S_cg_tilde = peak_shift ? S_cg(z[1], Δₚ, kₚ, C_α) : 0.0 + S_dir_tilde = direction ? S_dir(u, v, c_gp_x, c_gp_y, C_φ, Hₚ) : 0.0 + + z = @SVector [ + # energy + +ωₚ .* r_g^2 .* S_cg_tilde + ωₚ .* (Ĩ - D̃), + + # peak group velocity vector + -z[2] .* ωₚ .* r_g^2 .* S_cg_tilde + z[3] .* S_dir_tilde, + -z[3] .* ωₚ .* r_g^2 .* S_cg_tilde - z[2] .* S_dir_tilde, + + # D(z[2]) ~ -z[2] .* ωₚ .* r_g^2 .* S_cg_tilde + (z[3] + 0.001) .* S_dir_tilde, #* (-1), + # D(z[3]) ~ -z[3] .* ωₚ .* r_g^2 .* S_cg_tilde - (z[2] + 0.001) .* S_dir_tilde, #* (1), + + # propagation + propagation ? z[2] : 0.0, + propagation ? z[3] : 0.0 + ] + + if debug_output + additional_output = @SVector [ + Ĩ, + -D̃, + r_g^2 * S_cg_tilde, + Hₚ, + S_dir_tilde, + Δₚ, + c_gp_y + ] + z = vcat(z, additional_output) + end + + return z + + end + return particle_system_static + + else + + function particle_system(dz, z, params, t)#::MVector{5, Number} + + # forcing fields + #u = (u=u(x, y, t), v=v(x, y, t))::NamedTuple{(:u, :v),Tuple{Number,Number}} + lne, c̄_x, c̄_y, x, y = z + + r_g, C_α, g, C_e, C_φ = params.r_g, params.C_α, params.g, params.C_e, params.C_φ + #u = (u=u, v=v)::NamedTuple{(:u, :v),Tuple{Number,Number}} + u = u_wind(z[4], y, t)#::Number + v = v_wind(x, y, t)#::Number + + c̄ = speed(c̄_x, c̄_y) + u_speed = speed(u, v) + + # peak parameters + c_gp_speed, kₚ, ωₚ = c_g_conversions_vector(abs(c̄), r_g=r_g) ## <--- this one is slow!! + c_gp_x = c_g_conversions(c̄_x, r_g=r_g) + c_gp_y = c_g_conversions(c̄_y, r_g=r_g) + + # direction equations + α = α_func(u_speed, c_gp_speed) + Hₚ = H_β(αₚ(u, v, c_gp_x, c_gp_y), p) + Δₚ = Δ_β(αₚ(u, v, c_gp_x, c_gp_y)) + + # Source terms + Ĩ = input ? Ĩ_func(α, Hₚ, C_e) : 0.0 + D̃ = dissipation ? D̃_func_lne(lne, kₚ, e_T, n) : 0.0 + S_cg_tilde = peak_shift ? S_cg(lne, Δₚ, kₚ, C_α) : 0.0 + S_dir_tilde = direction ? S_dir(u, v, c_gp_x, c_gp_y, C_φ, Hₚ) : 0.0 + + #particle_equations::Vector{Number} = [ + # energy + dz[1] = +ωₚ .* r_g^2 .* S_cg_tilde + ωₚ .* (Ĩ - D̃) #- c̄ .* G_n, + + # peak group velocity vector + dz[2] = -c̄_x .* ωₚ .* r_g^2 .* S_cg_tilde + c̄_y .* S_dir_tilde #* (-1), + dz[3] = -c̄_y .* ωₚ .* r_g^2 .* S_cg_tilde - c̄_x .* S_dir_tilde #* (1), + + # D(c̄_x) ~ -c̄_x .* ωₚ .* r_g^2 .* S_cg_tilde + (c̄_y + 0.001) .* S_dir_tilde, #* (-1), + # D(c̄_y) ~ -c̄_y .* ωₚ .* r_g^2 .* S_cg_tilde - (c̄_x + 0.001) .* S_dir_tilde, #* (1), + + # propagation + dz[4] = propagation ? c̄_x : 0.0 + dz[5] = propagation ? c̄_y : 0.0 + + + if debug_output + additional_output = [ + Ĩ, + -D̃, + r_g^2 * S_cg_tilde, + #alpha_p ~ αₚ(u, c_gp_x, c_gp_y), + Hₚ, + #alpha ~ α, + S_dir_tilde, + Δₚ, + c_gp_y] + append!(dz, additional_output) + end + + return dz + + end + + return particle_system + + end + + +end + +# ------------ 1D ------------ +""" +particle_equations(u ; γ::Number=0.88, q::Number=-1/4.0 ) +Particle wave equations in 2D +inputs: + u: forcing field + γ: 0.88 + q: -1/4.0 + propagation: true + input: true + dissipation: true + peak_shift: true + info: false + +returns an ODE system as function particle_system(dz, z, params, t) that provides 3 element state vector tendency of: + z = [lne, c̄_x, x] + params can be a named tuple with the parameters or a vector + params = [r_g, C_α, g, C_e] +""" +function particle_equations(u_wind; γ::Number=0.88, q::Number=-1 / 4.0, + propagation=true, + input=true, + dissipation=true, + peak_shift=true, info=false) + + #t, x, c̄_x, lne, r_g, C_α, g, C_e = init_vars_1D() + + # Define basic constants for wave equation (invariant throughout the simulation) + p, q, n = magic_fractions(q) + e_T = e_T_func(γ, p, q, n)#, C_e=C_e) + #D = Differential(t) + + ### ---------------- start function here + function partice_system(dz, z, params, t) #<: Vector{Number} + #unpack0 + lne, c̄_x, x = z + #lne, c̄_x, x = z.lne, z.c̄_x, z.x + #r_g, C_α, g, C_e = params + r_g, C_α, g, C_e = params.r_g, params.C_α, params.g, params.C_e + + # forcing fields, need to be global scope? + u = u_wind(x, t) + #u = (u=u2(x, y, t), v=v2(x, y, t)) + + # trig-values # we only use scalers, not vectors + c̄ = c̄_x + u_speed = abs(u) + + # peak parameters + c_gp_speed, kₚ, ωₚ = c_g_conversions_vector(abs(c̄), r_g=r_g) + + # direction equations + α = α_func(u_speed, c_gp_speed) + Hₚ = H_β(α, p) + Δₚ = Δ_β(α) + + # Source terms + Ĩ = input ? Ĩ_func(α, Hₚ, C_e) : 0.0 + D̃ = dissipation ? D̃_func_lne(lne, kₚ, e_T, n) : 0.0 + S_cg_tilde = peak_shift ? S_cg(lne, Δₚ, kₚ, C_α) : 0.0 + c_group_x = propagation ? c̄_x : 0.0 + # no directional changes in 1D! + if info + println("alpha = ", α) + println("Hₚ = ", Hₚ) + println("Δₚ = ", Δₚ) + println("I_tilde = ", Ĩ) + println("D_tilde = ", D̃) + println("S_cg_tilde = ", S_cg_tilde) + println("c_tilde_x = ", c_group_x) + end + + # energy + dz[1] = +ωₚ .* r_g^2 .* S_cg_tilde + ωₚ .* (Ĩ - D̃) #- c̄ .* G_n, + #e * ωₚ .* (Ĩ - D̃)- e^3 *ξ / c̄ , + + # peak group velocity vector + dz[2] = - c̄_x .* ωₚ .* r_g^2 .* S_cg_tilde + + # propagation + dz[3] = c_group_x + + return dz + + end + + return partice_system +end + + +""" +particle_rays(u ; γ::Number=0.88, q::Number=-1/4.0 ) +Particle wave equations in 2D + +returns 3 element state vector of the particle system as vector: + [lne, c̄_x, x], lne, c̄_x, are constants +""" +function particle_rays(info=false) + + # no directional changes in 1D! + if info + println("c_x = ", c̄_x) + end + #D = Differential(t) + function partice_system(dz, z, params, t) #<: Vector{Number} + lne, c̄_x, x = z + # energy + dz[1] = 0 + # peak group velocity vector + dz[2] = 0 + # propagation + dz[3] = c̄_x + end + + return partice_system +end + + +# end of module +end From a343bfe103da48c7aca89bed97347588fac45cf0 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Wed, 28 Feb 2024 13:59:15 +0100 Subject: [PATCH 05/37] created new test case with no wind --- tests/T04_2D_box_2d_2.jl | 340 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 tests/T04_2D_box_2d_2.jl diff --git a/tests/T04_2D_box_2d_2.jl b/tests/T04_2D_box_2d_2.jl new file mode 100644 index 0000000..d6f90e9 --- /dev/null +++ b/tests/T04_2D_box_2d_2.jl @@ -0,0 +1,340 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +#using ModelingToolkit, DifferentialEquations +#using ModelingToolkit#: @register_symbolic +#using Plots +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v5 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.WaveGrowthModels2D + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures +using GLMakie + +using PiCLES.Operators.core_2D: GetGroupVelocity, speed +using PiCLES.Plotting.movie: init_movie_2D_box_plot + +using Revise +# debugging: +#using ProfileView + +# %% +save_path = "plots/tests/T04_box_2d/" +mkpath(save_path) + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 30minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + + +# u(x, y, t) = 0.01 + U10 * sin(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) +# v(x, y, t) = 0.01 - V10 * cos(t / (6*60*60 * 2π) ) * sin(x / 50e3) * sin(y / 50e3) +u_std= 2e3 *1 +v_std= 2e3 *1 +#u_func(x, y, t) = U10 * exp( - (x - 5e3)^2/ u_std^2) * exp( - (y - 5e3)^2/ v_std^2) * sin(t*2 / (1 * 60 * 60 * 2π)) +#v_func(x, y, t) = V10 * exp( - (x - 5e3)^2/ u_std^2) * exp( - (y - 5e3)^2/ v_std^2) * cos(t*2 / (1 * 60 * 60 * 2π) ) + +u_func(x, y, t) = 0 +v_func(x, y, t) = 0 + +# u_func(x, y, t) = 0.1 + IfElse.ifelse.( sin(t * 6 / (1 * 60 * 60 * 2π)) > 0 , +# sin(t * 6 / (1 * 60 * 60 * 2π)) *U10 * exp(-(x - 5e3)^2 / u_std^2) * exp(-(y - 5e3)^2 / v_std^2), +# 0.1) +# v_func(x, y, t) = 0.1 + IfElse.ifelse.(sin(t * 3 / (1 * 60 * 60 * 2π)) > 0, +# 0.0, +# -0.0) + +# u_func(x, y, t) = IfElse.ifelse.(x .< 5e3, U10, 0.2) + y * 0 + t * 0 +# v_func(x, y, t) = (IfElse.ifelse.(x .< 5e3, V10, 0.2) + y * 0) .* cos(t * 3 / (1 * 60 * 60 * 2π)) + +# this shuold hopefully work +# u(x, y, t) = x * 0 + y * 0 + t * 0/ DT + 5.0 +# v(x, y, t) = x * 0 + y * 0 + t * 0/ DT + 10.0 + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) +#typeof(u_func(1e3, 1e3, 11)) +#typeof(winds.u(x,y,t)) + +# u2 = winds.u(x, y, t) +# typeof(u2) +# typeof(winds.u(x, y, t)) +# %% + +grid = TwoDGrid(10e3, 31, 10e3, 31) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +#heatmap( v.(mesh.x, mesh.y, 0) ) + + +Revise.retry() + +# define variables based on particle equation + +#ProfileView.@profview +#ProfileView.@profview +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=true); +#particle_equations = PW3.particle_equations_vec5(u, v, u, v, γ=0.88, q=Const_ID.q); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +#WindSeamin = FetchRelations.get_minimal_windsea(u(0, 0, 0), v(0, 0, 0), DT / 2) +#WindSeamin = FetchRelations.get_initial_windsea(u(0, 0, 0), v(0, 0, 0), DT/5) +lne_local = log(WindSeamin["E"]) +cg_u_local = WindSeamin["cg_bar_x"] +cg_v_local = WindSeamin["cg_bar_y"] + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local,#log(FetchRelations.Eⱼ(0.1, DT)), + #maximum energy threshold + log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(lne_local, cg_u_local, cg_v_local, 0.0, 0.0) + +# Define grid +#grid = TwoDGrid(150e3, 50, 150e3, 50) + +# gridmesh = [(i, j) for i in gn.x, j in gn.y]; +# mesh.x = [i for i in gn.x, j in gn.y]; +# mesh.y = [j for i in gn.x, j in gn.y]; +# # mesh.x = mesh.x[1:3:end, 1:3:end]; +# # mesh.y = mesh.y[1:3:end, 1:3:end]; + + +# plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(u.(mesh.x, mesh.y, 0))) + +# plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(v.(mesh.x, mesh.y, 0))) +# %% build model +Revise.retry() + + +wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type="wind_sea", # default_ODE_parameters + periodic_boundary=false, + boundary_type="same", + #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), + movie=true) + + +### build Simulation +#wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=4hours)#1hours) +wave_simulation = Simulation(wave_model, Δt=20minutes, stop_time=1hour)#1hours) +initialize_simulation!(wave_simulation) + + +#init_state_store!(wave_simulation, save_path) +#wave_simulation.model.MovieState = wave_simulation.model.State + +@time run!(wave_simulation, cash_store=true, debug=true) +#reset_simulation!(wave_simulation) +# run simulation +#ProfileView.@profview run!(wave_simulation, cash_store=true, debug=true) + + +istate = wave_simulation.store.store[end]; +p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, istate[:, :, 1]) + + +# %% +# show all Failed particles +using PiCLES.Utils: ParticleTools + +Revise.retry() +DD = ParticleTools.ParticleToDataframe(wave_simulation.model.FailedCollection) + +DD_stats = ParticleTools.ParticleStatsToDataframe(wave_simulation.model.FailedCollection) + +#sum(DD_stats.boundary) + +function plot_state_and_error_points(wave_simulation, FailedTable) + plt.plot() + + p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(wave_simulation.model.State[:, :, 1])) + + for xy in FailedTable.position_xy + x = xy[1] / 1e3 + y = xy[2] / 1e3 + plt.scatter!((x, y), color="red", label="wind") + end + + plt.plot!(legend=:none, title="c_g", ylabel="cg m/s", xlabel="position index x") |> display +end + +plot_state_and_error_points(wave_simulation, DD_stats) +# %% + +## testing single ODES +PF = wave_simulation.model.FailedCollection[end] +PF.Particle +#PF.Particle.ODEIntegrator.u = [-15.441984291167334, 0.006707651986269529, 0.003889144130029894, 4000.0, 2333.3333333333335] +PF.Particle.ODEIntegrator.u +PF.Particle.ODEIntegrator.t +PF.Particle.ODEIntegrator.sol.t +PF.Particle.ODEIntegrator.sol.u +PF.Particle.ODEIntegrator.sol.prob.u0 + +using PiCLES.Operators.core_2D: Get_u_FromShared, GetVariablesAtVertex +S_state = Get_u_FromShared(PF.Particle, wave_simulation.model.MovieState) +ui = GetVariablesAtVertex(S_state, PF.Particle.position_xy[1], PF.Particle.position_xy[2]) + +usel = PF.Particle.ODEIntegrator.sol.prob.u0 +t_sel = PF.Particle.ODEIntegrator.sol.u +index, weight = PIC.compute_weights_and_index(grid, usel[4], usel[5]) + +using PiCLES: ParticleInCell as PIC +index, weight = PIC.compute_weights_and_index(grid, PF.Particle.ODEIntegrator.u[4], PF.Particle.ODEIntegrator.u[5]) + + +# try manual solution with the same initial conditions +using DifferentialEquations + +#PF.Particle.ODEIntegrator.u = ui +ui2 = copy(PF.Particle.ODEIntegrator.sol.prob.u0) +reinit!(PF.Particle.ODEIntegrator, ui2, erase_sol=false, reset_dt=false, reinit_cache=true) +u_modified!(PF.Particle.ODEIntegrator, true) +#auto_dt_reset!(PF.Particle.ODEIntegrator) +PF.Particle.ODEIntegrator.t +# set_t!(PF.Particle.ODEIntegrator, PF.Particle.ODEIntegrator.sol.t[end]) + +wind_tuple = winds.u(PF.Particle.position_xy[1], PF.Particle.position_xy[2], PF.Particle.ODEIntegrator.t), winds.v(PF.Particle.position_xy[1], PF.Particle.position_xy[2], PF.Particle.ODEIntegrator.t) +step!(PF.Particle.ODEIntegrator, DT, true) +PF.Particle.ODEIntegrator.u + + +function set_u_and_t!(integrator, u_new, t_new) + integrator.u = u_new + integrator.t = t_new +end + +#5min +DT = 5min#wave_simulation.model.ODEsettings.timestep +ui2 +set_u_and_t!(PF.Particle.ODEIntegrator, ui2, 0.0) +auto_dt_reset!(PF.Particle.ODEIntegrator) +step!(PF.Particle.ODEIntegrator, DT, true) +PF.Particle.ODEIntegrator.u + +#index, weight = PIC.compute_weights_and_index(grid, PF.Particle.ODEIntegrator.u[4], PF.Particle.ODEIntegrator.u[5]) + +#PF.Particle.ODEIntegrator.sol +#wave_simulation.model.winds.u() + +# %% +#PF.Particle.boundary +Revise.retry() + +istate = wave_simulation.store.store[end]; +#istate = wave_simulation.store.store[5]; +#wave_simulation.model.ParticleCollection[105] + +cg= GetGroupVelocity(istate) +p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, istate[:, :, 1]) + +# %% +p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, cg.c_x) + +# %% +#pcolormesh in Julia +# gn = TwoDGridNotes(grid); + +# gridmesh = [(i,j) for i in gn.x, j in gn.y]; +# mesh.x = [i for i in gn.x, j in gn.y]; +# mesh.y = [j for i in gn.x, j in gn.y]; +# mesh.x = mesh.x[1:3:end, 1:3:end]; +# mesh.y = mesh.y[1:3:end, 1:3:end]; + +# %% +# %% + +p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, wave_simulation.model.State[:, :, 2]) + +# plt.quiver!(p1, mesh.x / 1e3, mesh.y / 1e3, quiver=(wave_simulation.model.State[1:3:end, 1:3:end, 2] * 20, wave_simulation.model.State[1:3:end, 1:3:end, 3] * 20), color=:red, scale_unit=:data, label="wind") +# # scale_unit options: :width, :height, :x, :y, :xy, :data + +plt.contour(p1, gn.x / 1e3, gn.y / 1e3, u.(mesh.x, mesh.y, wave_simulation.model.clock.time), color="white") + +# # heatmap(wave_simulation.model.State[:, :, 2]) +# # heatmap(wave_simulation.model.State[:, :, 3]) + + +#sqrt( wave_simulation.model.winds.v.(mesh.x, mesh.y, 0.0)^2 + wave_simulation.model.winds.u.(mesh.x, mesh.y, 0.0)^2) + +# %% +Revise.retry() +wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type="wind_sea", # default_ODE_parameters + periodic_boundary=false, + boundary_type="same", + #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), + movie=true) + +wave_simulation = Simulation(wave_model, Δt=5minutes, stop_time=4hours)#1hours) +initialize_simulation!(wave_simulation) + +#reset_simulation!(wave_simulation, particle_initials=copy(wave_model.ODEdefaults)) + +fig, n = init_movie_2D_box_plot(wave_simulation, name_string= "Rotating Stationary Winds") + +#wave_simulation.stop_time += 1hour +N = 250 +record(fig, save_path*"T02_2D_totating_winds_nonper.gif", 1:N, framerate=10) do i + @info "Plotting frame $i of $N..." + #@time for _ = 1:10 + #run!(wave_simulation, store=false) + @info wave_simulation.model.clock + movie_time_step!(wave_simulation.model, wave_simulation.Δt) + #coupled_time_step!(ocean_simulation, ice_simulation) + #end + n[] = 1 +end From 46e55398ad638825af57cd5728e35b91df0a8585 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Fri, 1 Mar 2024 10:43:17 +0100 Subject: [PATCH 06/37] created test case and fixed minor issue associated with it --- src/Simulations/run.jl | 2 +- tests/T04_2D_box_2d_2.jl | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index 96cfc72..585e867 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -1,4 +1,4 @@ -using ..Operators.core_1D: ParticleDefaults +using ..Operators.core_2D: ParticleDefaults using ..Operators.core_1D: SeedParticle! as SeedParticle1D! using ..Operators.core_2D: SeedParticle! as SeedParticle2D! diff --git a/tests/T04_2D_box_2d_2.jl b/tests/T04_2D_box_2d_2.jl index d6f90e9..210e882 100644 --- a/tests/T04_2D_box_2d_2.jl +++ b/tests/T04_2D_box_2d_2.jl @@ -35,7 +35,7 @@ using Revise #using ProfileView # %% -save_path = "plots/tests/T04_box_2d/" +save_path = "plots/tests/T04_box_2d_2/" mkpath(save_path) # % Parameters @@ -58,8 +58,8 @@ v_std= 2e3 *1 #u_func(x, y, t) = U10 * exp( - (x - 5e3)^2/ u_std^2) * exp( - (y - 5e3)^2/ v_std^2) * sin(t*2 / (1 * 60 * 60 * 2π)) #v_func(x, y, t) = V10 * exp( - (x - 5e3)^2/ u_std^2) * exp( - (y - 5e3)^2/ v_std^2) * cos(t*2 / (1 * 60 * 60 * 2π) ) -u_func(x, y, t) = 0 -v_func(x, y, t) = 0 +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. # u_func(x, y, t) = 0.1 + IfElse.ifelse.( sin(t * 6 / (1 * 60 * 60 * 2π)) > 0 , # sin(t * 6 / (1 * 60 * 60 * 2π)) *U10 * exp(-(x - 5e3)^2 / u_std^2) * exp(-(y - 5e3)^2 / v_std^2), @@ -134,7 +134,7 @@ ODE_settings = PW.ODESettings( save_everystep=false) -default_particle = ParticleDefaults(lne_local, cg_u_local, cg_v_local, 0.0, 0.0) +default_particle = ParticleDefaults(1, 0, 2, 5000.0, 1500.0) # Define grid #grid = TwoDGrid(150e3, 50, 150e3, 50) @@ -157,7 +157,9 @@ wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, winds=winds, ODEsys=particle_system, ODEsets=ODE_settings, # ODE_settings - ODEinit_type="wind_sea", # default_ODE_parameters + #ODEinit_type="wind_sea", # default_ODE_parameters + #ODEinit_type="mininmal", + ODEinit_type=default_particle, periodic_boundary=false, boundary_type="same", #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), @@ -210,6 +212,7 @@ end plot_state_and_error_points(wave_simulation, DD_stats) # %% +plt.savefig(joinpath([save_path, "energy_plot_no_spread.png"])) ## testing single ODES PF = wave_simulation.model.FailedCollection[end] From 76a2cbb7e27c50cd1fbfbd2db182bc81eb6115e2 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Mon, 11 Mar 2024 10:25:31 +0100 Subject: [PATCH 07/37] Added support for angular spreading; Now it works, but some changes are left to do --- Project.toml | 2 + src/FetchRelations.jl | 4 +- src/Models/GeometricalOpticsModels.jl | 30 +- src/Operators/Operators.jl | 4 +- src/Operators/TimeSteppers.jl | 13 +- src/Operators/core_2D_spread.jl | 491 +++++++++++++++++++++++ src/Operators/mapping_2D.jl | 18 +- src/ParticleInCell.jl | 13 +- src/ParticleSystems/particle_waves_v6.jl | 3 +- src/Simulations/run.jl | 4 +- tests/T04_2D_box_2d_2.jl | 18 +- 11 files changed, 574 insertions(+), 26 deletions(-) create mode 100644 src/Operators/core_2D_spread.jl diff --git a/Project.toml b/Project.toml index 5b27d5d..7b03ad0 100644 --- a/Project.toml +++ b/Project.toml @@ -13,6 +13,7 @@ Callbacks = "db1e321a-d383-57b4-a664-0144fd54e973" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" +Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" GEMPIC = "b6d65c3a-4a4e-11e9-25d0-d309dc85ddeb" @@ -36,6 +37,7 @@ Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" ProfileView = "c46f51b8-102a-5cf2-8d2c-8597cb0e0da7" PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" SharedArrays = "1a1011a3-84de-559e-8e89-a11a2f7dc383" diff --git a/src/FetchRelations.jl b/src/FetchRelations.jl index 0f11512..736999e 100644 --- a/src/FetchRelations.jl +++ b/src/FetchRelations.jl @@ -339,7 +339,7 @@ Alias for default minimum Parameters. Takes wind just for the correct sign conve """ function MinimalParticle(U10::Number, time_scale::Number, type::String="JONSWAP") WindSeamin= get_minimal_windsea(U10, time_scale, type) - return [log(WindSeamin["E"]), WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0, 0] + return [log(WindSeamin["E"]), WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0, 0, 1.] end """ @@ -348,7 +348,7 @@ Alias for default minimum Parameters. Takes wind just for the correct sign conve """ function MinimalParticle(U10::Number, V10::Number, time_scale::Number, type::String="JONSWAP") WindSeamin= get_minimal_windsea(U10, V10, time_scale, type) - return [log(WindSeamin["E"]), WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0, 0] + return [log(WindSeamin["E"]), WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0, 0, 1.] end """ diff --git a/src/Models/GeometricalOpticsModels.jl b/src/Models/GeometricalOpticsModels.jl index 4a766b7..8870a15 100644 --- a/src/Models/GeometricalOpticsModels.jl +++ b/src/Models/GeometricalOpticsModels.jl @@ -10,7 +10,7 @@ using ModelingToolkit: get_states, ODESystem #using core_1D: MarkedParticleInstance using ...ParticleMesh: OneDGrid, OneDGridNotes, TwoDGrid, TwoDGridNotes -using ...Operators.core_2D: ParticleDefaults as ParticleDefaults2D +using ...Operators.core_2D_spread: ParticleDefaults as ParticleDefaults2D #using core_2D: SeedParticle! as SeedParticle2D! using ...Operators.mapping_2D @@ -40,6 +40,7 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, Clo, Int, stat, + Pan, PCollection, FPC, Ovar, @@ -61,7 +62,8 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, clock::Clo dims::Int # number of dimensions - State::stat # state of of the model at each grid point, for each layer it contains, energy, positions, group speed + State::stat # state of of the model at each grid point, for each layer it contains, energy, positions, group speed and directional spreading + ParticlesAtNode::Pan # list of the particles to regrid at each node ParticleCollection::PCollection # Collection (list) of Particles FailedCollection::FPC # Collection (list) of Particles that failed to integrate @@ -137,13 +139,34 @@ function GeometricalOptics(; grid::TwoDGrid, # initialize state {SharedArray} given grid and layers # Number of state variables - Nstate = 3 + Nstate = 4 if layers > 1 State = SharedArray{Float64,4}(grid.Nx, grid.Ny, Nstate, layers) else State = SharedArray{Float64,3}(grid.Nx, grid.Ny, Nstate) end + if layers > 1 + ParticlesAtNode = Array{Array{Array{Array{Vector{Float64},1},1},1},1}() + for i in 1:grid.Nx + push!(ParticlesAtNode, []) + for j in 1:grid.Ny + push!(ParticlesAtNode[i], []) + for _ in 1:layers + push!(ParticlesAtNode[i][j], []) + end + end + end + else + ParticlesAtNode = Array{Array{Array{Vector{Float64},1},1},1}() + for i in 1:grid.Nx + push!(ParticlesAtNode, []) + for _ in 1:grid.Ny + push!(ParticlesAtNode[i], []) + end + end + end + if ODEinit_type isa ParticleDefaults2D ODEdefaults = ODEinit_type elseif ODEinit_type == "wind_sea" @@ -221,6 +244,7 @@ function GeometricalOptics(; grid::TwoDGrid, clock, # ??? 2, # This is a 2D model State, + ParticlesAtNode, ParticleCollection, FailedCollection, ODEvars, diff --git a/src/Operators/Operators.jl b/src/Operators/Operators.jl index c22e182..bb7fae1 100644 --- a/src/Operators/Operators.jl +++ b/src/Operators/Operators.jl @@ -1,6 +1,6 @@ module Operators -export core_1D, core_2D, custom_structures, mapping_1D, mapping_2D, TimeSteppers +export core_1D, core_2D, core_2D_spread, custom_structures, mapping_1D, mapping_2D, TimeSteppers export init_z0_to_State! using SharedArrays @@ -23,6 +23,7 @@ include("utils.jl") include("initialize.jl") include("core_1D.jl") include("core_2D.jl") +include("core_2D_spread.jl") include("mapping_1D.jl") include("mapping_2D.jl") @@ -33,6 +34,7 @@ include("TimeSteppers.jl") using .core_1D using .core_2D +using .core_2D_spread using .mapping_1D using .mapping_2D using .TimeSteppers diff --git a/src/Operators/TimeSteppers.jl b/src/Operators/TimeSteppers.jl index 8c25505..eaaeb7a 100644 --- a/src/Operators/TimeSteppers.jl +++ b/src/Operators/TimeSteppers.jl @@ -107,7 +107,7 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb @threads for a_particle in model.ParticleCollection #@info a_particle.position_ij - mapping_2D.advance!( a_particle, model.State, FailedCollection, + mapping_2D.advance!( a_particle, model.ParticlesAtNode, model.State, FailedCollection, model.grid, model.winds, Δt, model.ODEsettings.log_energy_maximum, model.ODEsettings.wind_min_squared, @@ -115,6 +115,17 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb model.ODEdefaults) end + for (i,j) in [(i,j) for i in 1:model.grid.Nx for j in 1:model.grid.Ny] + weights = [model.ParticlesAtNode[i][j][k][1] for k in 1:length(model.ParticlesAtNode[i][j])] + values = [model.ParticlesAtNode[i][j][k][2] for k in 1:length(model.ParticlesAtNode[i][j])] + if length(weights) > 0 + model.State[i,j,4] = sum(weights .* values) / sum(weights) + + for k in 1:length(model.ParticlesAtNode[i][j]) + pop!(model.ParticlesAtNode[i][j]) + end + end + end if debug print("mean energy after advance ", mean_of_state(model), "\n") diff --git a/src/Operators/core_2D_spread.jl b/src/Operators/core_2D_spread.jl new file mode 100644 index 0000000..90c79e7 --- /dev/null +++ b/src/Operators/core_2D_spread.jl @@ -0,0 +1,491 @@ +module core_2D_spread + +using DifferentialEquations: OrdinaryDiffEq.ODEIntegrator, OrdinaryDiffEq.ODEProblem, init +using ModelingToolkit: ODESystem ## depriciate when MTK is removed + +using SharedArrays +using DocStringExtensions + +# Particle-Node interaction +export GetParticleEnergyMomentum, GetVariablesAtVertex, Get_u_FromShared, ParticleDefaults, InitParticleInstance +export InitParticleValues + +#include("../Utils/FetchRelations.jl") +using ...FetchRelations + +using ...Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance + + +# using ..particle_waves_v3: init_vars +# t, x, y, c̄_x, c̄_y, lne, Δn, Δφ_p, r_g, C_α, C_φ, g, C_e = init_vars() + +using ...custom_structures: ParticleInstance1D, ParticleInstance2D, MarkedParticleInstance + +export init_z0_to_State! +include("initialize.jl") + +# Callbacks +export wrap_pos!, periodic_BD_single_PI!, show_pos!, periodic_condition_x +include("utils.jl") + +### particle defaults ### +""" +ParticleDefaults +Structure holds default particles +# Fields +$(DocStringExtensions.FIELDS) +""" +mutable struct ParticleDefaults + "log energy" + lne::Float64 + "zonal velocity" + c̄_x::Float64 + "meridional velocity" + c̄_y::Float64 + "x Position" + x::Float64 + "y Position" + y::Float64 + "angular spreading" + angular_σ::Float64 +end + +Base.copy(s::ParticleDefaults) = ParticleDefaults(s.lne, s.c̄_x, s.c̄_y, s.x, s.y, s.angular_σ) +initParticleDefaults(s::ParticleDefaults) = [s.lne, s.c̄_x, s.c̄_y, s.x, s.y, s.angular_σ] + +""" + + +""" + +######### Particle --> Node | 2D ########## + + +""" +GetParticleEnergyMomentum(PI) + +""" +function GetParticleEnergyMomentum(PI) + ui_lne, ui_c̄_x, ui_c̄_y, ui_x, ui_y, ui_angular_σ = PI.ODEIntegrator.u + + ui_e = exp(ui_lne) + c_speed = speed(ui_c̄_x, ui_c̄_y) + m_x = ui_c̄_x * ui_e / c_speed^2 / 2 + m_y = ui_c̄_y * ui_e / c_speed^2 / 2 + + return ui_e, m_x, m_y, ui_angular_σ +end + +function GetParticleEnergyMomentum(PI::AbstractParticleInstance) + return GetParticleEnergyMomentum(PI.ODEIntegrator.u) +end + +function GetParticleEnergyMomentum(zi::Dict) + return GetParticleEnergyMomentum([zi[lne], zi[c̄_x], zi[c̄_y], zi[x], zi[y], zi[angular_σ]]) +end + +function GetParticleEnergyMomentum(zi::ParticleDefaults) + return GetParticleEnergyMomentum([zi.lne, zi.c̄_x, zi.c̄_y, zi.x, zi.y, zi.angular_σ]) +end + +""" +GetParticleEnergyMomentum(PI) + +""" +function GetParticleEnergyMomentum(z0::Vector{Float64}) + + ui_lne, ui_c̄_x, ui_c̄_y, ui_x, ui_y, ui_angular_σ =z0 + ui_e = exp(ui_lne) + c_speed = speed(ui_c̄_x, ui_c̄_y) + m_x = ui_c̄_x * ui_e / c_speed^2 / 2 + m_y = ui_c̄_y * ui_e / c_speed^2 / 2 + + return [ui_e, m_x, m_y, ui_angular_σ] +end + +speed(x::Float64, y::Float64) = sqrt(x^2 + y^2) + +######### node--> Particle ########## + +""" +GetVariablesAtVertex(i_State::Vector{Float64}, x::Float64, y::Float64, Δn::Float64, Δφ_p::Float64 ) +i_state: [e, m_x, m_y] state vector at node +x, y: coordinates of the vertex + +""" +function GetVariablesAtVertex(i_State::Vector{Float64}, x::Float64, y::Float64) + e, m_x, m_y, sigma = i_State + m_amp = speed(m_x, m_y) + c_x = m_x * e / (2 * m_amp^2) + c_y = m_y * e / (2 * m_amp^2) + + return [log(e), c_x, c_y, x, y, sigma] +end + + +""" returns node state from shared array, given paritcle index """ +Get_u_FromShared(PI::AbstractParticleInstance, S::SharedArray,) = S[PI.position_ij[1], PI.position_ij[2], :] + +""" +GetGroupVelocity(i_State::Vector{Float64}) +i_state: [e, m_x, m_y] state vector at node +""" +function GetGroupVelocity(i_State) + e = i_State[:,:,1] + m_x = i_State[:,:,2] + m_y = i_State[:,:,3] + m_amp = speed.(m_x, m_y) + c_x = m_x .* e ./ (2 .* m_amp.^2) + c_y = m_y .* e ./ (2 .* m_amp.^2) + + return (c_x=c_x, c_y=c_y) +end + + +###### seed particles ##### + + +""" +InitParticleInstance(model::WaveGrowth1D, z_initials, pars, ij, boundary_flag, particle_on ; cbSets=nothing) +wrapper function to initalize a particle instance + inputs: + model is an initlized ODESytem + z_initials is the initial state of the ODESystem + pars are the parameters of the ODESystem + ij is the (i,j) tuple that of the initial position + boundary_flag is a boolean that indicates if the particle is on the boundary + particle_on is a boolean that indicates if the particle is on + chSet (optional) is the set of callbacks the ODE can have +""" +function InitParticleInstance(model, z_initials, ODE_settings, ij, boundary_flag, particle_on; cbSets=Nothing) + + # converty to ordered named tuple + ODE_parameters = NamedTuple{Tuple(Symbol.(keys(ODE_settings.Parameters)))}(values(ODE_settings.Parameters)) + + z_initials = initParticleDefaults(z_initials) + # create ODEProblem + problem = ODEProblem(model, z_initials, (0.0, ODE_settings.total_time), ODE_parameters) + # inialize problem + # works best with abstol = 1e-4,reltol=1e-3,maxiters=1e4, + integrator = init( + problem, + ODE_settings.solver, + saveat=ODE_settings.saving_step, + abstol=ODE_settings.abstol, + adaptive=ODE_settings.adaptive, + dt = ODE_settings.dt, + dtmin=ODE_settings.dtmin, + force_dtmin=ODE_settings.force_dtmin, + maxiters=ODE_settings.maxiters, + reltol=ODE_settings.reltol, + callback=ODE_settings.callbacks, + save_everystep=ODE_settings.save_everystep) + return ParticleInstance2D(ij, (z_initials[4], z_initials[5]), integrator, boundary_flag, particle_on) +end + +""" +InitParticleInstance(model::ODESystem, z_initials, pars, ij, boundary_flag, particle_on ; cbSets=nothing) +wrapper function to initalize a particle instance + inputs: + model is an initlized ODESytem + z_initials is the initial state of the ODESystem + pars are the parameters of the ODESystem + ij is the (i,j) tuple that of the initial position + boundary_flag is a boolean that indicates if the particle is on the boundary + particle_on is a boolean that indicates if the particle is on + chSet (optional) is the set of callbacks the ODE can have +""" +function InitParticleInstance(model::ODESystem, z_initials, ODE_settings, ij, boundary_flag, particle_on; cbSets=Nothing) + + z_initials = initParticleDefaults(z_initials) + # create ODEProblem + problem = ODEProblem(model, z_initials, (0.0, ODE_settings.total_time), ODE_settings.Parameters) + # inialize problem + # works best with abstol = 1e-4,reltol=1e-3,maxiters=1e4, + integrator = init( + problem, + ODE_settings.solver, + saveat=ODE_settings.saving_step, + abstol=ODE_settings.abstol, + adaptive=ODE_settings.adaptive, + dt=ODE_settings.dt, + dtmin=ODE_settings.dtmin, + force_dtmin=ODE_settings.force_dtmin, + maxiters=ODE_settings.maxiters, + reltol=ODE_settings.reltol, + callback=ODE_settings.callbacks, + save_everystep=ODE_settings.save_everystep) + return ParticleInstance2D(ij, (z_initials[4], z_initials[5]), integrator, boundary_flag, particle_on) +end + + + + +""" +InitParticleValues(defaults:: Union{Nothing,ParticleDefaults}, ij::Tuple, gridnote::OneDGridNotes, u, v, DT) + +Find initial conditions for particle. Used at the beginning of the experiment. + inputs: + defaults Dict with variables of the state vector, these will be replaced in this function + ij index of the grid point + gridnote grid to determine the position in the grid + winds NamedTuple (u,v) with interp. functions for wind values + DT time step of model, used to determine fetch laws +""" +function InitParticleValues( + defaults::PP, + xy::Tuple{Float64, Float64}, + uv::Tuple{Number, Number}, + DT) where {PP<:Union{Nothing,ParticleDefaults}} + + #i,j = ij + xx, yy = xy + + if defaults == nothing + + if speed(uv[1], uv[2]) > sqrt(2) + # defaults are not defined and there is wind + + # take in local wind velocities + WindSeaMin = FetchRelations.get_initial_windsea(uv[1], uv[2], DT) + # seed particle given fetch relations + lne = log(WindSeaMin["E"]) + c̄_x = WindSeaMin["cg_bar_x"] + c̄_y = WindSeaMin["cg_bar_y"] + angular_σ = π/8 + + particle_on = true + else + # defaults are not defined and there is no wind + u_min = FetchRelations.MinimalParticle(uv[1], uv[2], DT) + lne = u_min[1] + c̄_x = u_min[2] + c̄_y = u_min[3] + angular_σ = π/8 + + particle_on = false + end + + # initialize particle instance based on above devfined values + particle_defaults = ParticleDefaults(lne, c̄_x, c̄_y, xx, yy, angular_σ) + else + particle_defaults = defaults + particle_on = true + end + + #@show defaults + return particle_defaults, particle_on +end + + +# --------------------------- up to here for now (remove MTK)--------------------------- # + +""" +ResetParticleValues(PI::AbstractParticleInstance, particle_defaults::Union{Nothing,ParticleDefaults,Vector{Float64}}, ODE_settings::ODESettings, gridnote::OneDGridNotes, winds, DT) + +Reset the state of a particle instance + inputs: + PI ParticleInstance + particle_defaults Dict with variables of the state vector, these will be replaced in this function + ODE_settings ODESettings type + gridnote grid to determine the position in the grid + winds NamedTuple (u,v) with interp. functions for wind values + DT time step of model, used to determine fetch laws +returns: + dict or vector +""" +function ResetParticleValues( + defaults::PP, + PI::AbstractParticleInstance, + wind_tuple, + DT, vector=true) where {PP<:Union{Nothing,ParticleDefaults,Vector{Float64}}} + + if defaults == nothing # this is boundary_defaults = "wind_sea" + #@info "init particles from fetch relations: $z_i" + #particle_defaults = Dict{Num,Float64}() + #xx, yy = PI.position_xy[1], PI.position_xy[2] + # take in local wind velocities + u_init, v_init = wind_tuple[1], wind_tuple[2] + #winds.u(xx, yy, 0), winds.v(xx, yy, 0) + + WindSeaMin = FetchRelations.get_initial_windsea(u_init, v_init, DT) + # seed particle given fetch relations + particle_defaults = ParticleDefaults(log(WindSeaMin["E"]), WindSeaMin["cg_bar_x"], WindSeaMin["cg_bar_y"], PI.position_xy[1], PI.position_xy[2], π/8) + elseif typeof(defaults) == Vector{Float64} # this is for the case of minimal wind sea + particle_defaults = defaults + particle_defaults[4] = PI.position_xy[1] + particle_defaults[5] = PI.position_xy[2] + else + particle_defaults = defaults + end + + #@show defaults + if vector + return initParticleDefaults(particle_defaults) + else + return particle_defaults + end + +end +""" +check_boundary_point(i, boundary, periodic_boundary) +checks where ever or not point is a boundary point. +returns Bool +""" +function check_boundary_point(i, boundary, periodic_boundary) + return periodic_boundary ? false : (i in boundary) +end + + + + +# """ +# SeedParticle!(ParticleCollection ::Vector{Any}, State::SharedMatrix, i::Int64, +# particle_system::ODESystem, particle_defaults::Union{ParticleDefaults,Nothing}, ODE_settings, +# GridNotes, winds, DT:: Float64, Nx:: Int, boundary::Vector{Int}, periodic_boundary::Bool) + +# Seed Pickles to ParticleColletion and State +# """ +# function SeedParticle!( +# ParticleCollection::Vector{Any}, +# State::SharedArray, +# ij::Tuple{Int, Int}, + +# particle_system::SS, +# particle_defaults::PP, +# ODE_settings, #particle_waves_v3.ODESettings type + +# GridNotes, # ad type of grid note +# winds, # interp winds +# DT::Float64, + +# boundary::Vector{T}, +# periodic_boundary::Bool) where {T<:Union{Int,Any,Nothing,Int64},PP<:Union{ParticleDefaults,Nothing},SS<:Union{ODESystem,Any}} + +# xx, yy = GridNotes.x[ij[1]], GridNotes.y[ij[2]] + + +# #uv = winds.u(xx, yy, 0)::Union{Num,Float64}, winds.v(xx, yy, 0)::Union{Num,Float64} +# uv = winds.u(xx, yy, 0)::Float64, winds.v(xx, yy, 0)::Float64 + +# # define initial condition +# z_i, particle_on = InitParticleValues(particle_defaults, (xx,yy), uv, DT) +# # check if point is boundary point +# boundary_point = check_boundary_point(ij, boundary, periodic_boundary) +# #@info "boundary?", boundary_point + +# # if boundary_point +# # #@info "boundary point", boundary_point, particle_on +# # # if boundary point, then set particle to off +# # particle_on = false +# # end + +# # add initial state to State vector +# if particle_on +# init_z0_to_State!(State, ij, GetParticleEnergyMomentum(z_i)) +# end + +# # Push Inital condition to collection +# push!(ParticleCollection, +# InitParticleInstance( +# particle_system, +# z_i, +# ODE_settings, +# ij, +# boundary_point, +# particle_on)) +# nothing +# end + + +""" +SeedParticle(State::SharedMatrix, i::Int64, + particle_system::ODESystem, particle_defaults::Union{ParticleDefaults,Nothing}, ODE_settings, + GridNotes, winds, DT:: Float64, Nx:: Int, boundary::Vector{Int}, periodic_boundary::Bool) + +return ParicleInstance that can be pushed to ParticleColletion +""" +function SeedParticle( + State::SharedArray, + ij::Tuple{Int, Int}, + + particle_system::SS, + particle_defaults::PP, + ODE_settings, #particle_waves_v3.ODESettings type + + GridNotes, # ad type of grid note + winds, # interp winds + DT::Float64, + + boundary::Vector{T}, + periodic_boundary::Bool) where {T<:Union{Int,Any,Nothing,Int64},PP<:Union{ParticleDefaults,Nothing},SS<:Union{ODESystem,Any}} + + xx, yy = GridNotes.x[ij[1]], GridNotes.y[ij[2]] + + #uv = winds.u(xx, yy, 0)::Union{Num,Float64}, winds.v(xx, yy, 0)::Union{Num,Float64} + uv = winds.u(xx, yy, 0.0)::Float64, winds.v(xx, yy, 0.0)::Float64 + + # define initial condition + z_i, particle_on = InitParticleValues(particle_defaults, (xx,yy), uv, DT) + # check if point is boundary point + boundary_point = check_boundary_point(ij, boundary, periodic_boundary) + #@info "boundary?", boundary_point + + # if boundary_point + # #@info "boundary point", boundary_point, particle_on + # # if boundary point, then set particle to off + # particle_on = false + # end + + # add initial state to State vector + if particle_on + init_z0_to_State!(State, ij, GetParticleEnergyMomentum(z_i)) + end + + return InitParticleInstance( + particle_system, + z_i, + ODE_settings, + ij, + boundary_point, + particle_on) + + end + + +""" +SeedParticle!(ParticleCollection ::Vector{Any}, State::SharedMatrix, i::Int64, + particle_system::ODESystem, particle_defaults::Union{ParticleDefaults,Nothing}, ODE_settings, + GridNotes, winds, DT:: Float64, Nx:: Int, boundary::Vector{Int}, periodic_boundary::Bool) + +Seed Pickles to ParticleColletion and State +""" +function SeedParticle!( + ParticleCollection::Vector{Any}, + State::SharedArray, + ij::Tuple{Int, Int}, + + particle_system::SS, + particle_defaults::PP, + ODE_settings, #particle_waves_v3.ODESettings type + + GridNotes, # ad type of grid note + winds, # interp winds + DT::Float64, + + boundary::Vector{T}, + periodic_boundary::Bool) where {T<:Union{Int,Any,Nothing,Int64},PP<:Union{ParticleDefaults,Nothing},SS<:Union{ODESystem,Any}} + + # Push Inital condition to collection + push!(ParticleCollection, + SeedParticle(State, ij, + particle_system, particle_defaults, ODE_settings, #particle_waves_v3.ODESettings type + GridNotes, winds, DT, + boundary, periodic_boundary)) + nothing +end + + + +# end of module +end \ No newline at end of file diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index 4669dfb..90f1a33 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -3,6 +3,7 @@ module mapping_2D using SharedArrays using DifferentialEquations using Printf +using Random, Distributions using ...ParticleMesh: TwoDGrid, TwoDGridNotes import ...ParticleInCell as PIC @@ -11,7 +12,7 @@ using ...FetchRelations using ...custom_structures: ParticleInstance1D, ParticleInstance2D, MarkedParticleInstance -using ..core_2D: GetParticleEnergyMomentum, GetVariablesAtVertex, Get_u_FromShared, ResetParticleValues, ParticleDefaults +using ..core_2D_spread: GetParticleEnergyMomentum, GetVariablesAtVertex, Get_u_FromShared, ResetParticleValues, ParticleDefaults using ...Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, AbstractODESettings @@ -35,7 +36,7 @@ S Shared array where particles are stored G (TwoDGrid) Grid that defines the nodepositions """ -function ParticleToNode!(PI::AbstractParticleInstance, S::SharedArray, G::TwoDGrid, periodic_boundary::Bool) +function ParticleToNode!(PI::AbstractParticleInstance, particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, S::SharedArray, G::TwoDGrid, periodic_boundary::Bool) #u[4], u[5] are the x and y positions of the particle index_positions, weights = PIC.compute_weights_and_index(G, PI.ODEIntegrator.u[4], PI.ODEIntegrator.u[5]) @@ -43,7 +44,7 @@ function ParticleToNode!(PI::AbstractParticleInstance, S::SharedArray, G::TwoDGr #@show index_positions u_state = GetParticleEnergyMomentum(PI.ODEIntegrator.u) #@show u_state - PIC.push_to_grid!(S, u_state , index_positions, weights, G.Nx, G.Ny , periodic_boundary) + PIC.push_to_grid!(S, particlesAtNode, u_state , index_positions, weights, G.Nx, G.Ny , periodic_boundary) nothing end @@ -58,6 +59,14 @@ function ParticleToNode!(PI::AbstractParticleInstance, S::SharedMatrix, u_state: end function set_u_and_t!(integrator, u_new, t_new) + # adding a small deviation due to directional spreading + d = Normal(0, u_new[6]^2) + delta_phi = rand(d,1) + #delta_phi = 0.15 + c_x = u_new[2] * cos(delta_phi[1]) - u_new[3] * sin(delta_phi[1]) + c_y = u_new[2] * sin(delta_phi[1]) + u_new[3] * cos(delta_phi[1]) + u_new[2] = c_x + u_new[3] = c_y integrator.u = u_new integrator.t = t_new end @@ -91,6 +100,7 @@ end advance!(PI::AbstractParticleInstance, S::SharedMatrix{Float64}, G::TwoDGrid, DT::Float64) """ function advance!(PI::AbstractParticleInstance, + particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, S::SharedArray, Failed::Vector{AbstractMarkedParticleInstance}, G::TwoDGrid, @@ -197,7 +207,7 @@ function advance!(PI::AbstractParticleInstance, #if PI.ODEIntegrator.u[1] > -13.0 #ODEs.log_energy_minimum # the minimum enerçy is distributed to 4 neighbouring particles if PI.on - ParticleToNode!(PI, S, G, periodic_boundary) + ParticleToNode!(PI, particlesAtNode, S, G, periodic_boundary) end #return PI diff --git a/src/ParticleInCell.jl b/src/ParticleInCell.jl index 7cc49bf..7ac73d3 100644 --- a/src/ParticleInCell.jl +++ b/src/ParticleInCell.jl @@ -207,6 +207,7 @@ end ## 2D versions function push_to_grid!(grid::Matrix{Float64}, + particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, charge::Float64, index_pos::Tuple{Int, Int}, weights::Tuple{Float64, Float64}, @@ -218,6 +219,7 @@ function push_to_grid!(grid::Matrix{Float64}, end function push_to_grid!(grid::SharedArray{Float64, 3}, + particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, charge::Vector{Float64}, index_pos::Tuple{Int, Int}, weights::Tuple{Float64, Float64}, @@ -229,7 +231,8 @@ function push_to_grid!(grid::SharedArray{Float64, 3}, if sum(test_domain(index_pos, Nx, Ny)) != 2 return else - grid[ index_pos[1] , index_pos[2], : ] += weights[1] * weights[2] * charge + push!(particlesAtNode[index_pos[1]][index_pos[2]], [weights[1] * weights[2], charge[4]]) + grid[ index_pos[1] , index_pos[2], 1:3 ] += weights[1] * weights[2] * charge[1:3] end end @@ -250,6 +253,7 @@ end # wrapping over vectors of charges, index positions and weights function push_to_grid!(grid::SharedArray{Float64,3}, + particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, charge::Vector{Float64}, index_pos::Vector{Tuple{Int, Int}}, weights::Vector{Tuple{Float64, Float64}}, @@ -257,7 +261,7 @@ function push_to_grid!(grid::SharedArray{Float64,3}, periodic::Bool=true) #@info "this is version D" for (i, w) in zip(index_pos, weights) - push_to_grid!(grid, charge , i, w , Nx, Ny, periodic) + push_to_grid!(grid, particlesAtNode, charge , i, w , Nx, Ny, periodic) end end @@ -270,6 +274,7 @@ end # wrapper over 1D Vecors of chanegs and (nested) index positions and weights function push_to_grid!(grid::SharedMatrix{Float64}, + particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, charge::Vector{Float64}, index_pos::Vector{Any}, weights::Vector{Any}, @@ -278,7 +283,7 @@ function push_to_grid!(grid::SharedMatrix{Float64}, #@info "this is version C" for (im, wm, c) in zip(index_pos, weights, charge) for (i, w) in zip(im, wm) - push_to_grid!(grid, c, i, w, Nx, periodic) + push_to_grid!(grid, particlesAtNode, c, i, w, Nx, periodic) end end end @@ -287,6 +292,7 @@ end # multiple index positions and 1 charge function push_to_grid!(grid::MM, + particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, charge::Vector{Float64}, index_pos::Vector{Int}, weights::Vector{Float64}, @@ -318,6 +324,7 @@ end # only 1 index position and 1 charge function push_to_grid!(grid::MM, + particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, charge::Float64, index_pos::Int, weights::Float64, diff --git a/src/ParticleSystems/particle_waves_v6.jl b/src/ParticleSystems/particle_waves_v6.jl index caa5a5d..a2878f0 100644 --- a/src/ParticleSystems/particle_waves_v6.jl +++ b/src/ParticleSystems/particle_waves_v6.jl @@ -408,7 +408,7 @@ function particle_equations(u_wind, v_wind; γ::Number=0.88, q::Number=-1 / 4.0, # forcing fields #u = (u=u(x, y, t), v=v(x, y, t))::NamedTuple{(:u, :v),Tuple{Number,Number}} - lne, c̄_x, c̄_y, x, y = z + lne, c̄_x, c̄_y, x, y, angular_σ = z r_g, C_α, g, C_e, C_φ = params.r_g, params.C_α, params.g, params.C_e, params.C_φ #u = (u=u, v=v)::NamedTuple{(:u, :v),Tuple{Number,Number}} @@ -448,6 +448,7 @@ function particle_equations(u_wind, v_wind; γ::Number=0.88, q::Number=-1 / 4.0, # propagation dz[4] = propagation ? c̄_x : 0.0 dz[5] = propagation ? c̄_y : 0.0 + dz[6] = 0 if debug_output diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index 585e867..6abb782 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -1,7 +1,7 @@ -using ..Operators.core_2D: ParticleDefaults +using ..Operators.core_2D_spread: ParticleDefaults using ..Operators.core_1D: SeedParticle! as SeedParticle1D! -using ..Operators.core_2D: SeedParticle! as SeedParticle2D! +using ..Operators.core_2D_spread: SeedParticle! as SeedParticle2D! using ..Architectures: Abstract2DModel, Abstract1DModel using ..ParticleMesh: OneDGrid, OneDGridNotes, TwoDGrid, TwoDGridNotes diff --git a/tests/T04_2D_box_2d_2.jl b/tests/T04_2D_box_2d_2.jl index 210e882..9e3fc74 100644 --- a/tests/T04_2D_box_2d_2.jl +++ b/tests/T04_2D_box_2d_2.jl @@ -8,16 +8,16 @@ Pkg.activate(".") import Plots as plt using Setfield, IfElse -using PiCLES.ParticleSystems: particle_waves_v5 as PW +using PiCLES.ParticleSystems: particle_waves_v6 as PW import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity using PiCLES.Operators: TimeSteppers using PiCLES.Simulations using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.WaveGrowthModels2D +using PiCLES.Models.GeometricalOpticsModels using Oceananigans.TimeSteppers: Clock, tick! import Oceananigans: fields @@ -27,7 +27,7 @@ import Oceananigans.Utils: prettytime using PiCLES.Architectures using GLMakie -using PiCLES.Operators.core_2D: GetGroupVelocity, speed +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed using PiCLES.Plotting.movie: init_movie_2D_box_plot using Revise @@ -134,7 +134,7 @@ ODE_settings = PW.ODESettings( save_everystep=false) -default_particle = ParticleDefaults(1, 0, 2, 5000.0, 1500.0) +default_particle = ParticleDefaults(1, 0, 2, 5000.0, 1500.0, π/8) # Define grid #grid = TwoDGrid(150e3, 50, 150e3, 50) @@ -153,7 +153,7 @@ default_particle = ParticleDefaults(1, 0, 2, 5000.0, 1500.0) Revise.retry() -wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, winds=winds, ODEsys=particle_system, ODEsets=ODE_settings, # ODE_settings @@ -175,7 +175,7 @@ initialize_simulation!(wave_simulation) #init_state_store!(wave_simulation, save_path) #wave_simulation.model.MovieState = wave_simulation.model.State -@time run!(wave_simulation, cash_store=true, debug=true) +@time run!(wave_simulation, cash_store=true, debug=false) #reset_simulation!(wave_simulation) # run simulation #ProfileView.@profview run!(wave_simulation, cash_store=true, debug=true) @@ -224,7 +224,7 @@ PF.Particle.ODEIntegrator.sol.t PF.Particle.ODEIntegrator.sol.u PF.Particle.ODEIntegrator.sol.prob.u0 -using PiCLES.Operators.core_2D: Get_u_FromShared, GetVariablesAtVertex +using PiCLES.Operators.core_2D_spread: Get_u_FromShared, GetVariablesAtVertex S_state = Get_u_FromShared(PF.Particle, wave_simulation.model.MovieState) ui = GetVariablesAtVertex(S_state, PF.Particle.position_xy[1], PF.Particle.position_xy[2]) @@ -312,7 +312,7 @@ plt.contour(p1, gn.x / 1e3, gn.y / 1e3, u.(mesh.x, mesh.y, wave_simulation.model # %% Revise.retry() -wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, winds=winds, ODEsys=particle_system, ODEsets=ODE_settings, # ODE_settings From 8cb38bb51fd206fe789c02154ce9e021cce58b6f Mon Sep 17 00:00:00 2001 From: tomprotin Date: Mon, 18 Mar 2024 16:28:07 +0100 Subject: [PATCH 08/37] added the possibility to plot during run time; added angular spreading types and threshold structure --- src/Models/GeometricalOpticsModels.jl | 18 ++++++++++++++++++ src/Operators/mapping_2D.jl | 1 - src/Simulations/run.jl | 22 ++++++++++++++++++++++ tests/T04_2D_box_2d_2.jl | 12 ++++++++---- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/Models/GeometricalOpticsModels.jl b/src/Models/GeometricalOpticsModels.jl index 8870a15..fe81708 100644 --- a/src/Models/GeometricalOpticsModels.jl +++ b/src/Models/GeometricalOpticsModels.jl @@ -52,6 +52,10 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, bl_flag, bl, bl_type, + as_type, + as_thresh, + plt_steps, + plt_path, wnds, cur, Mstat} <: Abstract2DModel where {Mstat<:Union{Nothing,stat}, PCollection<:Union{Vector,Array}} @@ -78,6 +82,12 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, boundary::bl # List of boundary points boundary_defaults::bl_type # Dict{NUm, Float64} ODE defaults + angular_spreading_thresh::as_thresh # threshold for splitting + angular_spreading_type::as_type # type of angular spreading used + + plot_steps::plt_steps # Whether or not to plot the steps + plot_savepath::plt_path # The path to use for saving plots + winds::wnds # u, v, if needed u_x, u_y currents::cur # u, v, currents @@ -134,6 +144,10 @@ function GeometricalOptics(; grid::TwoDGrid, currents=nothing, # periodic_boundary=true, boundary_type="same", # or "minimal", "same", default is same, only used if periodic_boundary is false + angular_spreading_thresh=π/8, + angular_spreading_type="stochast", # or "geometrical" or "nonparametric" + plot_steps=false, + plot_savepath="", CBsets=nothing, movie=false) where {PP<:Union{ParticleDefaults2D,String}} @@ -255,6 +269,10 @@ function GeometricalOptics(; grid::TwoDGrid, minimal_state, periodic_boundary, boundary, boundary_defaults, + angular_spreading_thresh, + angular_spreading_type, + plot_steps, + plot_savepath, winds, currents, Mstat) diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index 90f1a33..b252e99 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -62,7 +62,6 @@ function set_u_and_t!(integrator, u_new, t_new) # adding a small deviation due to directional spreading d = Normal(0, u_new[6]^2) delta_phi = rand(d,1) - #delta_phi = 0.15 c_x = u_new[2] * cos(delta_phi[1]) - u_new[3] * sin(delta_phi[1]) c_y = u_new[2] * sin(delta_phi[1]) + u_new[3] * cos(delta_phi[1]) u_new[2] = c_x diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index 6abb782..e9424c0 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -14,6 +14,7 @@ using ..Operators.mapping_1D using ..Operators.mapping_2D using Statistics +import Plots as plt #using ThreadsX @@ -25,12 +26,22 @@ function mean_of_state(model::Abstract1DModel) return mean(model.State[:, 1]) end +function plot_state_and_error_points(wave_simulation, gn) + plt.plot() + + p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(wave_simulation.model.State[:, :, 1])) + + + plt.plot!(legend=:none, title="c_g", ylabel="cg m/s", xlabel="position index x") |> display +end + """ run!(sim::Simulation; store = false, pickup=false) main method to run the Simulation sim. Needs time_step! to be defined for the model, and push_state_to_storage! to be defined for the store. """ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) + save_path = sim.model.plot_savepath start_time_step = time_ns() @@ -65,6 +76,8 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) end end + grid_note = TwoDGridNotes(sim.model.grid) + while sim.running @@ -105,6 +118,15 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) end sim.running = sim.stop_time >= sim.model.clock.time ? true : false @info sim.model.clock + + if sim.model.plot_steps + @info "plot" + plot_state_and_error_points(sim, grid_note) + plt.savefig(joinpath([save_path, "energy_plot_no_spread_"*string(Int64(floor((sim.model.clock.time)/60)))*".png"])) + else + @info "not plot" + end + end end_time_step = time_ns() diff --git a/tests/T04_2D_box_2d_2.jl b/tests/T04_2D_box_2d_2.jl index 9e3fc74..62027e7 100644 --- a/tests/T04_2D_box_2d_2.jl +++ b/tests/T04_2D_box_2d_2.jl @@ -134,7 +134,7 @@ ODE_settings = PW.ODESettings( save_everystep=false) -default_particle = ParticleDefaults(1, 0, 2, 5000.0, 1500.0, π/8) +default_particle = ParticleDefaults(1, 1, 1, 1000.0, 1000.0, π/4) # Define grid #grid = TwoDGrid(150e3, 50, 150e3, 50) @@ -163,12 +163,16 @@ wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, periodic_boundary=false, boundary_type="same", #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), - movie=true) + movie=true, + plot_steps=true, + plot_savepath="plots/tests/T04_box_2d_2/geometrical", + angular_spreading_type="geometrical" + ) ### build Simulation #wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=4hours)#1hours) -wave_simulation = Simulation(wave_model, Δt=20minutes, stop_time=1hour)#1hours) +wave_simulation = Simulation(wave_model, Δt=2minutes, stop_time=30minutes)#1hours) initialize_simulation!(wave_simulation) @@ -187,7 +191,7 @@ p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, istate[:, :, 1]) # %% # show all Failed particles -using PiCLES.Utils: ParticleTools +using PiCLES.Utils: ParticleTools Revise.retry() DD = ParticleTools.ParticleToDataframe(wave_simulation.model.FailedCollection) From 65adacf63707ad4659bd2b7dc0414b663f8cbc98 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Mon, 18 Mar 2024 16:31:45 +0100 Subject: [PATCH 09/37] added full support for stochas and geometrical spreading types --- src/Operators/TimeSteppers.jl | 44 ++++++++++++++--- src/Operators/mapping_2D.jl | 92 ++++++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 9 deletions(-) diff --git a/src/Operators/TimeSteppers.jl b/src/Operators/TimeSteppers.jl index eaaeb7a..9836bf9 100644 --- a/src/Operators/TimeSteppers.jl +++ b/src/Operators/TimeSteppers.jl @@ -138,13 +138,43 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb end #@printf "re-mesh" - @threads for a_particle in model.ParticleCollection - mapping_2D.remesh!(a_particle, model.State, - model.winds, model.clock.time, - model.ODEsettings, Δt, - model.minimal_particle, - model.minimal_state, - model.ODEdefaults) + if model.angular_spreading_type == "stochast" + @threads for a_particle in model.ParticleCollection + mapping_2D.remesh!(a_particle, model.State, + model.winds, model.clock.time, + model.ODEsettings, Δt, + model.minimal_particle, + model.minimal_state, + model.ODEdefaults) + end + elseif model.angular_spreading_type == "geometrical" + i = 1 + particlesToBeReset = [] + + for _ in 1:length(model.ParticleCollection) + pos_ij = model.ParticleCollection[i].position_ij + big_enough = model.State[pos_ij[1], pos_ij[2],2]^2+model.State[pos_ij[1], pos_ij[2],3]^2>model.minimal_state[2] + if model.ParticleCollection[i].boundary || ~big_enough + i=i+1 + elseif !(model.ParticleCollection[i].position_ij in particlesToBeReset) + push!(particlesToBeReset, model.ParticleCollection[i].position_ij) + deleteat!(model.ParticleCollection, i) + end + end + @threads for a_particle in model.ParticleCollection + mapping_2D.remesh!(a_particle, model.State, + model.winds, model.clock.time, + model.ODEsettings, Δt, + model.minimal_particle, + model.minimal_state, + model.ODEdefaults) + end + @threads for (i,j) in particlesToBeReset + mapping_2D.remesh!(i, j, model, Δt) + end + @info particlesToBeReset + elseif model.angular_spreading_type == "nonparametric" + end if debug diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index b252e99..2e4d8b7 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -12,10 +12,10 @@ using ...FetchRelations using ...custom_structures: ParticleInstance1D, ParticleInstance2D, MarkedParticleInstance -using ..core_2D_spread: GetParticleEnergyMomentum, GetVariablesAtVertex, Get_u_FromShared, ResetParticleValues, ParticleDefaults +using ..core_2D_spread: GetParticleEnergyMomentum, GetVariablesAtVertex, Get_u_FromShared, ResetParticleValues, ParticleDefaults, InitParticleInstance -using ...Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, AbstractODESettings +using ...Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, AbstractODESettings, Abstract2DModel ###### remeshing routines ############ @@ -237,6 +237,94 @@ function remesh!(PI::ParticleInstance2D, S::SharedArray{Float64,3}, #return PI end +""" + remesh!(PI::ParticleInstance2D, S::SharedMatrix{Float64, 3}) + Wrapper function that does everything necessary to remesh the particles. + - pushes the Node State to particle instance +""" +function remesh!(i::Int64, j::Int64, model::Abstract2DModel, DT::Float64) + winds = model.winds + ti = model.clock.time + grid = model.grid + + x = grid.xmin + grid.dx*i + y = grid.ymin + grid.dy*j + winds_i::Tuple{Float64,Float64} = winds.u(x, y, ti), winds.v(x, y, ti) + + NodeToParticle!(i, j, x, y, model, winds_i, DT) +end + +""" + NodeToParticle!(PI::AbstractParticleInstance, S::SharedMatrix) +Pushes node value to particle: +- If Node value is smaller than a minimal value, the particle is renintialized +- If Node value is okey, it is converted to state variable and pushed to particle. +- The particle position is set to the node positions +""" +function NodeToParticle!(i::Int64, j::Int64, x::Float64, y::Float64, model::Abstract2DModel, wind_tuple::Tuple{Float64,Float64}, DT::Float64) + S = model.State + minimal_particle = model.minimal_particle + minimal_state = model.minimal_state + wind_min_squared = model.ODEsettings.wind_min_squared + default_particle = model.ODEdefaults + e_min_log = model.ODEsettings.log_energy_minimum + current_is_boundary = i==0 || i==model.grid.Nx || j==0 || j==model.grid.Ny + + + # load data from shared array + u_state = S[i, j, :] + + #last_t = ti + last_t = model.clock.time + # minimal_state[1] is the minmal Energy + # minimal_state[2] is the minmal momentum squared + if ~current_is_boundary & (u_state[1] >= minimal_state[1]) & (speed_square(u_state[2], u_state[3]) >= minimal_state[2]) # all interior nodes: convert note to particle values and push to ODEIntegrator + nNewParticles = Int64((u_state[4] ÷ model.angular_spreading_thresh)*2+1) + if nNewParticles == 1 + nNewParticles = 3 + end + midParticleInd = Int64(nNewParticles ÷ 2 + 1) + ui = GetVariablesAtVertex(u_state, x, y) + energies = [exp(-(k-midParticleInd)^2/(2*π*midParticleInd)^2) for k in 1:nNewParticles] + energies = energies ./ sum(energies) .* exp(ui[1]) + + for k in 1:nNewParticles + delta_phi = (k-midParticleInd)/midParticleInd*u_state[4] + c_x = ui[2] * cos(delta_phi) - ui[3] * sin(delta_phi) + c_y = ui[2] * sin(delta_phi) + ui[3] * cos(delta_phi) + z_init = ParticleDefaults(log(energies[k]), c_x, c_y, x, y, u_state[4]/nNewParticles) + push!(model.ParticleCollection,InitParticleInstance(model.ODEsystem, z_init, model.ODEsettings, (i,j), false, true)) + end + + elseif ~PI.boundary & (speed_square(wind_tuple[1], wind_tuple[2]) >= wind_min_squared) #minimal windsea is not big enough but local winds are strong enough #(u_state[1] < exp(e_min_log)) | PI.boundary + # test if particle is below energy threshold, or + # if particle is at the boundary + + ui = ResetParticleValues(default_particle, PI, wind_tuple, DT) # returns winds sea given DT and winds + reinit!(PI.ODEIntegrator, ui, erase_sol=false, reset_dt=true, reinit_cache=true)#, reinit_callbacks=true) + reset_PI_t!(PI, ti=last_t) + + PI.on = true + + elseif PI.boundary & (speed_square(wind_tuple[1], wind_tuple[2]) >= wind_min_squared) # at the boundary, reset particle if winds are strong enough + + ui = ResetParticleValues(default_particle, PI, wind_tuple, DT) # returns winds sea given DT and winds + reinit!(PI.ODEIntegrator, ui, erase_sol=false, reset_dt=true, reinit_cache=true)#, reinit_callbacks=true) + reset_PI_t!(PI, ti=last_t) + + PI.on = true + + + else # particle is below energy threshold & on boundary + #PI.ODEIntegrator.u = ResetParticleValues(minimal_particle, PI, wind_tuple, DT) + # if ~PI.boundary + # @info u_state + # end + PI.on = false + end + +end + """ NodeToParticle!(PI::AbstractParticleInstance, S::SharedMatrix) From f527f4fe5a65a134a66e703d146b64660b0c4616 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Tue, 19 Mar 2024 14:55:45 +0100 Subject: [PATCH 10/37] Added a model parameter storing the number of particles to launch at each node when using the "nonparametric" spreading type --- src/Models/GeometricalOpticsModels.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Models/GeometricalOpticsModels.jl b/src/Models/GeometricalOpticsModels.jl index fe81708..80950b5 100644 --- a/src/Models/GeometricalOpticsModels.jl +++ b/src/Models/GeometricalOpticsModels.jl @@ -56,6 +56,7 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, as_thresh, plt_steps, plt_path, + nPart, wnds, cur, Mstat} <: Abstract2DModel where {Mstat<:Union{Nothing,stat}, PCollection<:Union{Vector,Array}} @@ -87,6 +88,7 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, plot_steps::plt_steps # Whether or not to plot the steps plot_savepath::plt_path # The path to use for saving plots + n_particles_launch::nPart # Number of particles to launch from each node when using a nonparametric spreading type winds::wnds # u, v, if needed u_x, u_y currents::cur # u, v, currents @@ -148,6 +150,7 @@ function GeometricalOptics(; grid::TwoDGrid, angular_spreading_type="stochast", # or "geometrical" or "nonparametric" plot_steps=false, plot_savepath="", + n_particles_launch=5, CBsets=nothing, movie=false) where {PP<:Union{ParticleDefaults2D,String}} @@ -273,6 +276,7 @@ function GeometricalOptics(; grid::TwoDGrid, angular_spreading_type, plot_steps, plot_savepath, + n_particles_launch, winds, currents, Mstat) From 71ea18b2375541c5074475b5c9ed0c934981782b Mon Sep 17 00:00:00 2001 From: tomprotin Date: Fri, 14 Jun 2024 11:50:55 +0200 Subject: [PATCH 11/37] Non parametric method for wave propagation; also added some basic structures for the validation of the 1/r decay of energy density --- src/Models/GeometricalOpticsModels.jl | 15 +++- src/Operators/TimeSteppers.jl | 123 ++++++++++++++++++++++++-- src/Operators/core_2D_spread.jl | 12 ++- src/Operators/mapping_2D.jl | 73 ++++++++++----- src/ParticleInCell.jl | 25 ++++-- src/Simulations/Simulations.jl | 2 +- src/Simulations/run.jl | 77 ++++++++++++++-- tests/T04_2D_box_2d_2.jl | 24 +++-- 8 files changed, 293 insertions(+), 58 deletions(-) diff --git a/src/Models/GeometricalOpticsModels.jl b/src/Models/GeometricalOpticsModels.jl index 80950b5..cda08cd 100644 --- a/src/Models/GeometricalOpticsModels.jl +++ b/src/Models/GeometricalOpticsModels.jl @@ -42,6 +42,8 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, stat, Pan, PCollection, + PPool, + PtSrcList, FPC, Ovar, Osys, @@ -70,6 +72,8 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, State::stat # state of of the model at each grid point, for each layer it contains, energy, positions, group speed and directional spreading ParticlesAtNode::Pan # list of the particles to regrid at each node ParticleCollection::PCollection # Collection (list) of Particles + ParticlePool::PPool # Pool of particles (used for non parametric mode) + PointSourceList::PtSrcList # List of all the point sources of waves FailedCollection::FPC # Collection (list) of Particles that failed to integrate ODEvars::Ovar # list of variables in ODE system, have type Num from OrdinaryDiffEq and ModelingToolkit @@ -150,7 +154,7 @@ function GeometricalOptics(; grid::TwoDGrid, angular_spreading_type="stochast", # or "geometrical" or "nonparametric" plot_steps=false, plot_savepath="", - n_particles_launch=5, + n_particles_launch=150, CBsets=nothing, movie=false) where {PP<:Union{ParticleDefaults2D,String}} @@ -164,7 +168,7 @@ function GeometricalOptics(; grid::TwoDGrid, end if layers > 1 - ParticlesAtNode = Array{Array{Array{Array{Vector{Float64},1},1},1},1}() + ParticlesAtNode = Array{Array{Array{Array{Any,1},1},1},1}() for i in 1:grid.Nx push!(ParticlesAtNode, []) for j in 1:grid.Ny @@ -174,15 +178,18 @@ function GeometricalOptics(; grid::TwoDGrid, end end end + ParticlePool = Array{Array{Any,1},1}() else - ParticlesAtNode = Array{Array{Array{Vector{Float64},1},1},1}() + ParticlesAtNode = Array{Array{Array{Any,1},1},1}() for i in 1:grid.Nx push!(ParticlesAtNode, []) for _ in 1:grid.Ny push!(ParticlesAtNode[i], []) end end + ParticlePool = Array{Any,1}() end + PointSourceList = [] if ODEinit_type isa ParticleDefaults2D ODEdefaults = ODEinit_type @@ -263,6 +270,8 @@ function GeometricalOptics(; grid::TwoDGrid, State, ParticlesAtNode, ParticleCollection, + ParticlePool, + PointSourceList, FailedCollection, ODEvars, ODEsys, diff --git a/src/Operators/TimeSteppers.jl b/src/Operators/TimeSteppers.jl index 9836bf9..287893a 100644 --- a/src/Operators/TimeSteppers.jl +++ b/src/Operators/TimeSteppers.jl @@ -10,6 +10,9 @@ using Statistics using Base.Threads using Printf +using Random, Distributions +using ..core_2D_spread: ParticleDefaults, InitParticleInstance + using Oceananigans.TimeSteppers: tick! function mean_of_state(model::Abstract2DModel) @@ -105,6 +108,12 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb model.FailedCollection = FailedCollection end + for (i,j) in [(i,j) for i in 1:model.grid.Nx for j in 1:model.grid.Ny] + for k in 1:length(model.ParticlesAtNode[i][j]) + pop!(model.ParticlesAtNode[i][j]) + end + end + @threads for a_particle in model.ParticleCollection #@info a_particle.position_ij mapping_2D.advance!( a_particle, model.ParticlesAtNode, model.State, FailedCollection, @@ -120,10 +129,6 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb values = [model.ParticlesAtNode[i][j][k][2] for k in 1:length(model.ParticlesAtNode[i][j])] if length(weights) > 0 model.State[i,j,4] = sum(weights .* values) / sum(weights) - - for k in 1:length(model.ParticlesAtNode[i][j]) - pop!(model.ParticlesAtNode[i][j]) - end end end @@ -172,9 +177,117 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb @threads for (i,j) in particlesToBeReset mapping_2D.remesh!(i, j, model, Δt) end - @info particlesToBeReset + elseif model.angular_spreading_type == "nonparametric" + + # This next part needs to change + + """ + i=1 + particlesToBeReset = [] + particlesToBeResetIndex = [] + + for _ in 1:length(model.ParticleCollection) + pos_ij = model.ParticleCollection[i].position_ij + big_enough = model.State[pos_ij[1], pos_ij[2],2]^2+model.State[pos_ij[1], pos_ij[2],3]^2>model.minimal_state[2] + if model.ParticleCollection[i].boundary || ~big_enough + i=i+1 + else + if !(model.ParticleCollection[i].position_ij in particlesToBeResetIndex) + push!(particlesToBeResetIndex, model.ParticleCollection[i].position_ij) + end + deleteat!(model.ParticleCollection, i) + end + end + """ + """ + @threads for a_particle in model.ParticleCollection + mapping_2D.remesh!(a_particle, model.State, + model.winds, model.clock.time, + model.ODEsettings, Δt, + model.minimal_particle, + model.minimal_state, + model.ODEdefaults) + end + """ + + nPreviousParticles = 0 + model.ParticlePool = [] + + for (i,j) in [(i,j) for i in 1:model.grid.Nx for j in 1:model.grid.Ny] + locallen = length(model.ParticlesAtNode[i][j]) + nPreviousParticles += locallen + for k in 1:locallen + push!(model.ParticlePool, [deepcopy(model.ParticlesAtNode[i][j][k][3]), i, j, exp(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[1])*model.ParticlesAtNode[i][j][k][1]]) + end + end + + ParticuleEnergiesNorm = sum([model.ParticlePool[k][4] for k in 1:length(model.ParticlePool)]) + for k in 1:length(model.ParticlePool) + model.ParticlePool[k][4] = model.ParticlePool[k][4] / ParticuleEnergiesNorm + end + + energiesNormed = [model.ParticlePool[k][4] for k in 1:length(model.ParticlePool)] + a = Categorical(energiesNormed) + nNewParticles = model.n_particles_launch + particlesDrawn = rand(a, nNewParticles) + #new_energy_tot = sum([energiesNormed[k] for k in particlesDrawn]) + #energy_factor = totEnergyDomain[1] / new_energy_tot + + i = 1 + j = 0 + counter = 0 + for _ in 1:length(model.ParticleCollection) + if model.ParticleCollection[i].on + if counter >= nNewParticles + deleteat!(model.ParticleCollection, i) + j=j+1 + else + i=i+1 + end + counter +=1 + else + i=i+1 + end + end + #@info "removed particles :", j + #@info "new energy :", ParticuleEnergiesNorm + + #@info "particlesDrawn", model.ParticlePool[particlesDrawn[k]][1].ODEIntegrator.u[2] + + for k in 1:nNewParticles + i = model.ParticlePool[particlesDrawn[k]][2] + j = model.ParticlePool[particlesDrawn[k]][3] + x = model.grid.xmin + model.grid.dx*(i-1) + y = model.grid.ymin + model.grid.dy*(j-1) + #log_energy = log(totEnergyDomain[1]/nPreviousParticles) + log_energy = log(ParticuleEnergiesNorm/nNewParticles) + c_x = model.ParticlePool[particlesDrawn[k]][1].ODEIntegrator.u[2] + c_y = model.ParticlePool[particlesDrawn[k]][1].ODEIntegrator.u[3] + spreading = model.ParticlePool[particlesDrawn[k]][1].ODEIntegrator.u[6] + + #z_init = ParticleDefaults(log_energy, c_x, c_y, x, y, spreading) + model.ParticleCollection[end-k+1].position_ij = (i,j) + model.ParticleCollection[end-k+1].position_xy = (x,y) + model.ParticleCollection[end-k+1].ODEIntegrator.u[1] = log_energy + model.ParticleCollection[end-k+1].ODEIntegrator.u[2] = c_x + model.ParticleCollection[end-k+1].ODEIntegrator.u[3] = c_y + model.ParticleCollection[end-k+1].ODEIntegrator.u[4] = x + model.ParticleCollection[end-k+1].ODEIntegrator.u[5] = y + model.ParticleCollection[end-k+1].ODEIntegrator.u[6] = spreading + #push!(model.ParticleCollection,InitParticleInstance(model.ODEsystem, z_init, model.ODEsettings, (i,j), false, true)) + end + + #@info nPreviousParticles + #@info length(model.ParticleCollection) + + """ + @threads for k in eachindex(particlesToBeResetIndex) + i, j = particlesToBeResetIndex[k] + mapping_2D.remesh!(i, j, model, Δt) + end + """ end if debug diff --git a/src/Operators/core_2D_spread.jl b/src/Operators/core_2D_spread.jl index 90c79e7..a6ea0d1 100644 --- a/src/Operators/core_2D_spread.jl +++ b/src/Operators/core_2D_spread.jl @@ -53,6 +53,16 @@ end Base.copy(s::ParticleDefaults) = ParticleDefaults(s.lne, s.c̄_x, s.c̄_y, s.x, s.y, s.angular_σ) initParticleDefaults(s::ParticleDefaults) = [s.lne, s.c̄_x, s.c̄_y, s.x, s.y, s.angular_σ] +mutable struct PointSource + "particle to launch" + particleLaunch::ParticleDefaults + "first launch time" + firstTimeLaunched::Float64 +end + +Base.copy(s::PointSource) = PointSource(s.particleLaunch, s.lastTimeLaunched) +PointSource(s::PointSource) = [s.particleLaunch, s.lastTimeLaunched] + """ @@ -254,7 +264,7 @@ function InitParticleValues( c̄_y = WindSeaMin["cg_bar_y"] angular_σ = π/8 - particle_on = true + particle_on = false else # defaults are not defined and there is no wind u_min = FetchRelations.MinimalParticle(uv[1], uv[2], DT) diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index 2e4d8b7..d144764 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -36,15 +36,14 @@ S Shared array where particles are stored G (TwoDGrid) Grid that defines the nodepositions """ -function ParticleToNode!(PI::AbstractParticleInstance, particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, S::SharedArray, G::TwoDGrid, periodic_boundary::Bool) +function ParticleToNode!(PI::AbstractParticleInstance, particlesAtNode::Array{Array{Array{Any,1},1},1}, S::SharedArray, G::TwoDGrid, periodic_boundary::Bool) #u[4], u[5] are the x and y positions of the particle index_positions, weights = PIC.compute_weights_and_index(G, PI.ODEIntegrator.u[4], PI.ODEIntegrator.u[5]) #ui[1:2] .= PI.position_xy - #@show index_positions u_state = GetParticleEnergyMomentum(PI.ODEIntegrator.u) #@show u_state - PIC.push_to_grid!(S, particlesAtNode, u_state , index_positions, weights, G.Nx, G.Ny , periodic_boundary) + PIC.push_to_grid!(S, particlesAtNode, PI, u_state , index_positions, weights, G.Nx, G.Ny , periodic_boundary) nothing end @@ -99,7 +98,7 @@ end advance!(PI::AbstractParticleInstance, S::SharedMatrix{Float64}, G::TwoDGrid, DT::Float64) """ function advance!(PI::AbstractParticleInstance, - particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, + particlesAtNode::Array{Array{Array{Any,1},1},1}, S::SharedArray, Failed::Vector{AbstractMarkedParticleInstance}, G::TwoDGrid, @@ -247,8 +246,8 @@ function remesh!(i::Int64, j::Int64, model::Abstract2DModel, DT::Float64) ti = model.clock.time grid = model.grid - x = grid.xmin + grid.dx*i - y = grid.ymin + grid.dy*j + x = grid.xmin + grid.dx*(i-1) # A MODIFIER ??? Peut-etre changer i pour i-1 pour mettre bien à 0, pareil pour j + y = grid.ymin + grid.dy*(j-1) winds_i::Tuple{Float64,Float64} = winds.u(x, y, ti), winds.v(x, y, ti) NodeToParticle!(i, j, x, y, model, winds_i, DT) @@ -270,6 +269,10 @@ function NodeToParticle!(i::Int64, j::Int64, x::Float64, y::Float64, model::Abst e_min_log = model.ODEsettings.log_energy_minimum current_is_boundary = i==0 || i==model.grid.Nx || j==0 || j==model.grid.Ny + # definition of a norm 2 + norm(vec) = sqrt(sum([vec[i]^2 for i in eachindex(vec)])) + one_norm(vec) = sum([vec[i] for i in eachindex(vec)]) + # load data from shared array u_state = S[i, j, :] @@ -279,23 +282,49 @@ function NodeToParticle!(i::Int64, j::Int64, x::Float64, y::Float64, model::Abst # minimal_state[1] is the minmal Energy # minimal_state[2] is the minmal momentum squared if ~current_is_boundary & (u_state[1] >= minimal_state[1]) & (speed_square(u_state[2], u_state[3]) >= minimal_state[2]) # all interior nodes: convert note to particle values and push to ODEIntegrator - nNewParticles = Int64((u_state[4] ÷ model.angular_spreading_thresh)*2+1) - if nNewParticles == 1 - nNewParticles = 3 - end - midParticleInd = Int64(nNewParticles ÷ 2 + 1) - ui = GetVariablesAtVertex(u_state, x, y) - energies = [exp(-(k-midParticleInd)^2/(2*π*midParticleInd)^2) for k in 1:nNewParticles] - energies = energies ./ sum(energies) .* exp(ui[1]) - - for k in 1:nNewParticles - delta_phi = (k-midParticleInd)/midParticleInd*u_state[4] - c_x = ui[2] * cos(delta_phi) - ui[3] * sin(delta_phi) - c_y = ui[2] * sin(delta_phi) + ui[3] * cos(delta_phi) - z_init = ParticleDefaults(log(energies[k]), c_x, c_y, x, y, u_state[4]/nNewParticles) - push!(model.ParticleCollection,InitParticleInstance(model.ODEsystem, z_init, model.ODEsettings, (i,j), false, true)) + if model.angular_spreading_type == "geometrical" + nNewParticles = Int64((u_state[4] ÷ model.angular_spreading_thresh)*2+1) + if nNewParticles == 1 + nNewParticles = 3 + end + midParticleInd = Int64(nNewParticles ÷ 2 + 1) + ui = GetVariablesAtVertex(u_state, x, y) + energies = [exp(-(k-midParticleInd)^2/(2*π*midParticleInd)^2) for k in 1:nNewParticles] + energies = energies ./ sum(energies) .* exp(ui[1]) + + for k in 1:nNewParticles + delta_phi = (k-midParticleInd)/midParticleInd*u_state[4] + c_x = ui[2] * cos(delta_phi) - ui[3] * sin(delta_phi) + c_y = ui[2] * sin(delta_phi) + ui[3] * cos(delta_phi) + z_init = ParticleDefaults(log(energies[k]), c_x, c_y, x, y, u_state[4]/nNewParticles) + push!(model.ParticleCollection,InitParticleInstance(model.ODEsystem, z_init, model.ODEsettings, (i,j), false, true)) + end + elseif model.angular_spreading_type == "nonparametric" + nNewParticles = model.n_particles_launch + nPartToDrawFrom = length(model.ParticlesAtNode[i][j]) + energiesNormed = [model.ParticlesAtNode[i][j][k][1]*exp(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[1]) for k in 1:nPartToDrawFrom] + energiesNormed = energiesNormed / u_state[1] + a = Categorical(energiesNormed) + particlesDrawn = rand(a, nNewParticles) + new_energy_tot = sum([energiesNormed[k] for k in particlesDrawn]) + #@info "u_state = ", u_state[1] + #@info "new_energy_tot = ", new_energy_tot + #@info particlesDrawn + energy_factor = u_state[1] / new_energy_tot + #@info "new val = ", sum([energiesNormed[particlesDrawn[k]]*energy_factor for k in 1:nNewParticles]) + #@info model.ParticlesAtNode[i][j][particlesDrawn[1]][3].ODEIntegrator.u[4], model.ParticlesAtNode[i][j][particlesDrawn[1]][3].position_xy[1], model.ParticlesAtNode[i][j][particlesDrawn[1]][3].position_xy[1] + model.grid.dx + #@info model.ParticlesAtNode[i][j][particlesDrawn[1]][3].ODEIntegrator.u[5], model.ParticlesAtNode[i][j][particlesDrawn[1]][3].position_xy[2], model.ParticlesAtNode[i][j][particlesDrawn[1]][3].position_xy[2] + model.grid.dy + for k in 1:nNewParticles + + log_energy = log(energiesNormed[particlesDrawn[k]]*energy_factor) + c_x = model.ParticlesAtNode[i][j][particlesDrawn[k]][3].ODEIntegrator.u[2] + c_y = model.ParticlesAtNode[i][j][particlesDrawn[k]][3].ODEIntegrator.u[3] + spreading = model.ParticlesAtNode[i][j][particlesDrawn[k]][3].ODEIntegrator.u[6] + + z_init = ParticleDefaults(log_energy, c_x, c_y, x, y, spreading) + push!(model.ParticleCollection,InitParticleInstance(model.ODEsystem, z_init, model.ODEsettings, (i,j), false, true)) + end end - elseif ~PI.boundary & (speed_square(wind_tuple[1], wind_tuple[2]) >= wind_min_squared) #minimal windsea is not big enough but local winds are strong enough #(u_state[1] < exp(e_min_log)) | PI.boundary # test if particle is below energy threshold, or # if particle is at the boundary diff --git a/src/ParticleInCell.jl b/src/ParticleInCell.jl index 7ac73d3..59f47d0 100644 --- a/src/ParticleInCell.jl +++ b/src/ParticleInCell.jl @@ -7,6 +7,7 @@ using SharedArrays # %% using ..ParticleMesh +using ...Architectures: AbstractParticleInstance # Tolerance for comparison of real numbers: set it here! # Set parameters @@ -207,7 +208,8 @@ end ## 2D versions function push_to_grid!(grid::Matrix{Float64}, - particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, + particlesAtNode::Array{Array{Array{Any,1},1},1}, + PI::AbstractParticleInstance, charge::Float64, index_pos::Tuple{Int, Int}, weights::Tuple{Float64, Float64}, @@ -219,7 +221,8 @@ function push_to_grid!(grid::Matrix{Float64}, end function push_to_grid!(grid::SharedArray{Float64, 3}, - particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, + particlesAtNode::Array{Array{Array{Any,1},1},1}, + PI::AbstractParticleInstance, charge::Vector{Float64}, index_pos::Tuple{Int, Int}, weights::Tuple{Float64, Float64}, @@ -231,7 +234,7 @@ function push_to_grid!(grid::SharedArray{Float64, 3}, if sum(test_domain(index_pos, Nx, Ny)) != 2 return else - push!(particlesAtNode[index_pos[1]][index_pos[2]], [weights[1] * weights[2], charge[4]]) + push!(particlesAtNode[index_pos[1]][index_pos[2]], [weights[1] * weights[2], charge[4], PI]) grid[ index_pos[1] , index_pos[2], 1:3 ] += weights[1] * weights[2] * charge[1:3] end end @@ -253,7 +256,8 @@ end # wrapping over vectors of charges, index positions and weights function push_to_grid!(grid::SharedArray{Float64,3}, - particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, + particlesAtNode::Array{Array{Array{Any,1},1},1}, + PI::AbstractParticleInstance, charge::Vector{Float64}, index_pos::Vector{Tuple{Int, Int}}, weights::Vector{Tuple{Float64, Float64}}, @@ -261,7 +265,7 @@ function push_to_grid!(grid::SharedArray{Float64,3}, periodic::Bool=true) #@info "this is version D" for (i, w) in zip(index_pos, weights) - push_to_grid!(grid, particlesAtNode, charge , i, w , Nx, Ny, periodic) + push_to_grid!(grid, particlesAtNode, PI, charge , i, w , Nx, Ny, periodic) end end @@ -274,7 +278,8 @@ end # wrapper over 1D Vecors of chanegs and (nested) index positions and weights function push_to_grid!(grid::SharedMatrix{Float64}, - particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, + particlesAtNode::Array{Array{Array{Any,1},1},1}, + PI::AbstractParticleInstance, charge::Vector{Float64}, index_pos::Vector{Any}, weights::Vector{Any}, @@ -283,7 +288,7 @@ function push_to_grid!(grid::SharedMatrix{Float64}, #@info "this is version C" for (im, wm, c) in zip(index_pos, weights, charge) for (i, w) in zip(im, wm) - push_to_grid!(grid, particlesAtNode, c, i, w, Nx, periodic) + push_to_grid!(grid, particlesAtNode, PI, c, i, w, Nx, periodic) end end end @@ -292,7 +297,8 @@ end # multiple index positions and 1 charge function push_to_grid!(grid::MM, - particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, + particlesAtNode::Array{Array{Array{Any,1},1},1}, + PI::AbstractParticleInstance, charge::Vector{Float64}, index_pos::Vector{Int}, weights::Vector{Float64}, @@ -324,7 +330,8 @@ end # only 1 index position and 1 charge function push_to_grid!(grid::MM, - particlesAtNode::Array{Array{Array{Vector{Float64},1},1},1}, + particlesAtNode::Array{Array{Array{Any,1},1},1}, + PI::AbstractParticleInstance, charge::Float64, index_pos::Int, weights::Float64, diff --git a/src/Simulations/Simulations.jl b/src/Simulations/Simulations.jl index 964ba44..ac7cb47 100644 --- a/src/Simulations/Simulations.jl +++ b/src/Simulations/Simulations.jl @@ -3,7 +3,7 @@ module Simulations export Simulation export StateStore, CashStore, state_store, init_state_store!, push_state_to_storage!, AbstractStore, convert_store_to_tuple export add_winds_forcing_to_store!, reset_state_store!, show_stored_data, close_store!, EmptyStore, StateStore -export run!, reset_simulation!, initialize_simulation! +export run!, reset_simulation!, initialize_simulation!, initialize_wave_sources! export convert_store_to_tuple using ..Architectures: AbstractStore diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index e9424c0..1f2557c 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -1,4 +1,4 @@ -using ..Operators.core_2D_spread: ParticleDefaults +using ..Operators.core_2D_spread: ParticleDefaults, SeedParticle using ..Operators.core_1D: SeedParticle! as SeedParticle1D! using ..Operators.core_2D_spread: SeedParticle! as SeedParticle2D! @@ -29,10 +29,21 @@ end function plot_state_and_error_points(wave_simulation, gn) plt.plot() - p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(wave_simulation.model.State[:, :, 1])) - + energy = get_tot_energy_domain(wave_simulation) + p1 = plt.heatmap(gn.x, gn.y, transpose(wave_simulation.model.State[:, :, 1]), aspect_ratio=:equal, size=(1080, 1080))#,clim=(0,1)) + + plt.plot!(legend=:none, + title="total energy = "*string(round(energy,digits=3))*"; max = "*string(round(maximum(wave_simulation.model.State[:,:,1]), + digits=3))*"; pos = ("*string(argmax(wave_simulation.model.State[:,:,1])[1])*","* + string(argmax(wave_simulation.model.State[:,:,1])[2])*")", + ylabel="y position", + xlabel="x position", + xlims=(gn.xmin, gn.xmax), + ylims=(gn.ymin, gn.ymax)) |> display +end - plt.plot!(legend=:none, title="c_g", ylabel="cg m/s", xlabel="position index x") |> display +function get_tot_energy_domain(wave_simulation) + return sum(wave_simulation.model.State[:,:,1]) end """ @@ -76,7 +87,7 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) end end - grid_note = TwoDGridNotes(sim.model.grid) + gridnotes = TwoDGridNotes(sim.model.grid) while sim.running @@ -121,7 +132,7 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) if sim.model.plot_steps @info "plot" - plot_state_and_error_points(sim, grid_note) + plot_state_and_error_points(sim, gridnotes) plt.savefig(joinpath([save_path, "energy_plot_no_spread_"*string(Int64(floor((sim.model.clock.time)/60)))*".png"])) else @info "not plot" @@ -136,6 +147,15 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) end +function initialize_wave_sources!(sim::Simulation, list::Array{Any,1}) + if sim.verbose + @info "init particle sources..." + end + + sim.model.PointSourceList = list + + nothing +end """ initialize_simulation!(sim::Simulation) @@ -210,7 +230,7 @@ initialize the model.ParticleCollection based on the model.grid and the defaults If defaults is nothing, then the model.ODEdev is used. usually the initilization uses wind constitions to seed the particles. """ -function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose::Bool=false) where {PP<:Union{ParticleDefaults,Nothing}} +function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose::Bool=false) where {PP<:Union{ParticleDefaults,Array{Any,1},Nothing}} #defaults = isnothing(defaults) ? model.ODEdev : defaults if verbose @info "seed PiCLES ... \n" @@ -227,7 +247,7 @@ function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose:: ParticleCollection = [] SeedParticle_i = SeedParticle_mapper(SeedParticle2D!, ParticleCollection, model.State, - model.ODEsystem, defaults, model.ODEsettings, + model.ODEsystem, nothing, model.ODEsettings, gridnotes, model.winds, model.ODEsettings.timestep, model.boundary, model.periodic_boundary) @@ -245,6 +265,47 @@ function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose:: # end model.ParticleCollection = ParticleCollection + + if defaults isa ParticleDefaults + i = Int64(floor((defaults.x - model.grid.xmin) / model.grid.dx)) + 1 + j = Int64(floor((defaults.y - model.grid.ymin) / model.grid.dy)) + 1 + gridnotes = TwoDGridNotes(model.grid) + if model.angular_spreading_type == "nonparametric" + # if "nonparametric" is used, initialize a bigger number of particles at the original perturbation + n_part = model.n_particles_launch + for _ in 1:n_part + defaults_temp = deepcopy(defaults) + delta_phi = rand() * defaults_temp.angular_σ - 0.5*defaults_temp.angular_σ + c_x = defaults_temp.c̄_x * cos(delta_phi) - defaults_temp.c̄_y * sin(delta_phi) + c_y = defaults_temp.c̄_x * sin(delta_phi) + defaults_temp.c̄_y * cos(delta_phi) + defaults_temp.lne += -log(n_part) + defaults_temp.c̄_x = c_x + defaults_temp.c̄_y = c_y + push!(ParticleCollection, SeedParticle(model.State, + (i,j), model.ODEsystem, defaults_temp, + model.ODEsettings,gridnotes, model.winds, + model.ODEsettings.timestep, model.boundary, + model.periodic_boundary)) + end + else + push!(ParticleCollection, SeedParticle(model.State, + (i,j), model.ODEsystem, defaults, + model.ODEsettings,gridnotes, model.winds, + model.ODEsettings.timestep, model.boundary, + model.periodic_boundary)) + end + elseif defaults isa Array{Any,1} + for k in 1:length(defaults) + i = Int64(floor((defaults[k].x - model.grid.xmin) / model.grid.dx)) + 1 + j = Int64(floor((defaults[k].y - model.grid.ymin) / model.grid.dy)) + 1 + gridnotes = OneDGridNotes(model.grid) + push!(ParticleCollection, SeedParticle(model.State, + (i,j), model.ODEsystem, defaults[k], + model.ODEsettings,gridnotes, model.winds, + model.ODEsettings.timestep, model.boundary, + model.periodic_boundary)) + end + end nothing end diff --git a/tests/T04_2D_box_2d_2.jl b/tests/T04_2D_box_2d_2.jl index 62027e7..211b48d 100644 --- a/tests/T04_2D_box_2d_2.jl +++ b/tests/T04_2D_box_2d_2.jl @@ -11,7 +11,7 @@ using Setfield, IfElse using PiCLES.ParticleSystems: particle_waves_v6 as PW import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource using PiCLES.Operators: TimeSteppers using PiCLES.Simulations using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! @@ -102,12 +102,13 @@ Revise.retry() #ProfileView.@profview #ProfileView.@profview -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=true); +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); #particle_equations = PW3.particle_equations_vec5(u, v, u, v, γ=0.88, q=Const_ID.q); # define V4 parameters absed on Const NamedTuple: default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +plt.scalefontsizes(1.75) # define setting and standard initial conditions WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); @@ -134,7 +135,7 @@ ODE_settings = PW.ODESettings( save_everystep=false) -default_particle = ParticleDefaults(1, 1, 1, 1000.0, 1000.0, π/4) +default_particle = ParticleDefaults(1, 0, 2.12, 5000.0, 500.0, π/4) # Define grid #grid = TwoDGrid(150e3, 50, 150e3, 50) @@ -159,20 +160,25 @@ wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, ODEsets=ODE_settings, # ODE_settings #ODEinit_type="wind_sea", # default_ODE_parameters #ODEinit_type="mininmal", - ODEinit_type=default_particle, + #ODEinit_type=default_particle, periodic_boundary=false, boundary_type="same", #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), movie=true, plot_steps=true, - plot_savepath="plots/tests/T04_box_2d_2/geometrical", - angular_spreading_type="geometrical" + plot_savepath="plots/tests/T04_box_2d_2/nonparametric", + angular_spreading_type="nonparametric" + ,n_particles_launch=20 ) +PS1 = PointSource(default_particle,0.0) +SourcesList = Array{Any,1}() +push!(SourcesList, PS1) ### build Simulation #wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=4hours)#1hours) -wave_simulation = Simulation(wave_model, Δt=2minutes, stop_time=30minutes)#1hours) +wave_simulation = Simulation(wave_model, Δt=2minutes, stop_time=60minutes)#1hours) +initialize_wave_sources!(wave_simulation, SourcesList) initialize_simulation!(wave_simulation) @@ -181,7 +187,7 @@ initialize_simulation!(wave_simulation) @time run!(wave_simulation, cash_store=true, debug=false) #reset_simulation!(wave_simulation) -# run simulation +# run simulation2 #ProfileView.@profview run!(wave_simulation, cash_store=true, debug=true) @@ -216,7 +222,7 @@ end plot_state_and_error_points(wave_simulation, DD_stats) # %% -plt.savefig(joinpath([save_path, "energy_plot_no_spread.png"])) +#plt.savefig(joinpath([save_path, "energy_plot_no_spread.png"])) ## testing single ODES PF = wave_simulation.model.FailedCollection[end] From e73a983d78a602315d7063d683f7c0ee420836fe Mon Sep 17 00:00:00 2001 From: tomprotin Date: Mon, 14 Apr 2025 15:23:53 +0200 Subject: [PATCH 12/37] updating code for SIR --- .gitignore | 8 + Project.toml | 5 + src/Models/GeometricalOpticsModels.jl | 14 +- src/Operators/TimeSteppers.jl | 56 +++++- src/Operators/mapping_2D.jl | 8 +- src/Simulations/run.jl | 241 +++++++++++++++++++++++--- tests/test_case_1.jl | 117 +++++++++++++ tests/test_case_2.jl | 117 +++++++++++++ 8 files changed, 537 insertions(+), 29 deletions(-) create mode 100644 tests/test_case_1.jl create mode 100644 tests/test_case_2.jl diff --git a/.gitignore b/.gitignore index 5715b2b..09f9004 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,14 @@ Manifest.toml config/config.json plots/* +tests/test_boundary_effect.jl +tests/test_debug.jl +Manifest2.toml +paper1_final/* .DS_Store +test_case_*.html +test_case_3_batch1_copy.jl .ipynb* + +Description algorithme PiCLES/* diff --git a/Project.toml b/Project.toml index 7b03ad0..5395d73 100644 --- a/Project.toml +++ b/Project.toml @@ -8,10 +8,13 @@ AbstractPlotting = "537997a7-5e4e-5d89-9595-2241ea00577e" ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63" Atom = "c52e3926-4ff0-5f6e-af25-54175e0327b1" BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" Callbacks = "db1e321a-d383-57b4-a664-0144fd54e973" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" @@ -43,10 +46,12 @@ Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" SharedArrays = "1a1011a3-84de-559e-8e89-a11a2f7dc383" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" WebIO = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29" [compat] +Oceananigans = "0.91.6" julia = "1.10.0" [extras] diff --git a/src/Models/GeometricalOpticsModels.jl b/src/Models/GeometricalOpticsModels.jl index cda08cd..b8252c8 100644 --- a/src/Models/GeometricalOpticsModels.jl +++ b/src/Models/GeometricalOpticsModels.jl @@ -22,6 +22,8 @@ import Oceananigans: fields using Oceananigans.TimeSteppers: Clock using ...FetchRelations +using LinearAlgebra + #includet("mapping_1D.jl") # TO DO : check if all the modules imported above are necessary, for now I just copied the ones from WaveGrowthModels2D.jl @@ -56,8 +58,10 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, bl_type, as_type, as_thresh, + pb_cov_init, plt_steps, plt_path, + sve_part, nPart, wnds, cur, @@ -89,9 +93,13 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, angular_spreading_thresh::as_thresh # threshold for splitting angular_spreading_type::as_type # type of angular spreading used + proba_covariance_init::pb_cov_init # initial probability density 4x4 covariance matrix of particles plot_steps::plt_steps # Whether or not to plot the steps plot_savepath::plt_path # The path to use for saving plots + + save_particles::sve_part # Whether or not to save particle data + n_particles_launch::nPart # Number of particles to launch from each node when using a nonparametric spreading type winds::wnds # u, v, if needed u_x, u_y @@ -142,7 +150,7 @@ function GeometricalOptics(; grid::TwoDGrid, ODEsys, ODEvars=nothing, #needed for MTK for ODEsystem. will be depriciated later layers::Int=1, - clock=Clock{eltype(grid)}(0, 0, 1), + clock=Clock{eltype(grid)}(;time=0, last_Δt=0, last_stage_Δt=1), ODEsets::AbstractODESettings=nothing, # ODE_settings ODEinit_type::PP= "wind_sea", # default_ODE_parameters minimal_particle=nothing, # minimum particle the model falls back to if a particle fails to integrate @@ -152,8 +160,10 @@ function GeometricalOptics(; grid::TwoDGrid, boundary_type="same", # or "minimal", "same", default is same, only used if periodic_boundary is false angular_spreading_thresh=π/8, angular_spreading_type="stochast", # or "geometrical" or "nonparametric" + proba_covariance_init = Matrix(I,4,4)*10^(-50), plot_steps=false, plot_savepath="", + save_particles=false, n_particles_launch=150, CBsets=nothing, movie=false) where {PP<:Union{ParticleDefaults2D,String}} @@ -283,8 +293,10 @@ function GeometricalOptics(; grid::TwoDGrid, boundary, boundary_defaults, angular_spreading_thresh, angular_spreading_type, + proba_covariance_init, plot_steps, plot_savepath, + save_particles, n_particles_launch, winds, currents, diff --git a/src/Operators/TimeSteppers.jl b/src/Operators/TimeSteppers.jl index 287893a..75791be 100644 --- a/src/Operators/TimeSteppers.jl +++ b/src/Operators/TimeSteppers.jl @@ -12,9 +12,12 @@ using Printf using Random, Distributions using ..core_2D_spread: ParticleDefaults, InitParticleInstance +using ...custom_structures: ParticleInstance2D using Oceananigans.TimeSteppers: tick! +using DataFrames, CSV, Dates + function mean_of_state(model::Abstract2DModel) return mean(model.State[:, :, 1]) end @@ -26,6 +29,34 @@ end ################# 1D #################### +function write_particles_to_csv(wave_model, Δt) + sec=string(Int64(floor((wave_model.clock.time+Δt)/60))) + dec=string(Int64(floor(10*((wave_model.clock.time+Δt)/60-floor((wave_model.clock.time+Δt)/60))))) + save_path = wave_model.plot_savepath + + nParticles = wave_model.n_particles_launch + @info wave_model.clock.time/60 + + parts = wave_model.ParticleCollection[(end-nParticles+1):end] + + logE = zeros(nParticles) + cx = zeros(nParticles) + cy = zeros(nParticles) + x = zeros(nParticles) + y = zeros(nParticles) + for i in 1:nParticles + logE[i] = parts[i].ODEIntegrator[1] + cx[i] = parts[i].ODEIntegrator[2] + cy[i] = parts[i].ODEIntegrator[3] + x[i] = parts[i].ODEIntegrator[4] + y[i] = parts[i].ODEIntegrator[5] + end + + data = DataFrame(id=1:nParticles, logE = logE, cx = cx, cy = cy, x = x, y = y) + data2 = Tables.table(transpose(wave_model.State[:, :, 1])) + CSV.write(save_path*"/data/particles_"*sec*","*dec*".csv", data) + CSV.write(save_path*"/data/mesh_values_"*sec*","*dec*".csv", data2) +end """ time_step!(model, Δt; callbacks=nothing) @@ -123,7 +154,11 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb model.periodic_boundary, model.ODEdefaults) end - + + if model.save_particles && length(model.ParticleCollection) > 0 + write_particles_to_csv(model, Δt) + end + for (i,j) in [(i,j) for i in 1:model.grid.Nx for j in 1:model.grid.Ny] weights = [model.ParticlesAtNode[i][j][k][1] for k in 1:length(model.ParticlesAtNode[i][j])] values = [model.ParticlesAtNode[i][j][k][2] for k in 1:length(model.ParticlesAtNode[i][j])] @@ -215,11 +250,22 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb nPreviousParticles = 0 model.ParticlePool = [] - for (i,j) in [(i,j) for i in 1:model.grid.Nx for j in 1:model.grid.Ny] + @threads for (i,j) in [(i,j) for i in 1:model.grid.Nx for j in 1:model.grid.Ny] locallen = length(model.ParticlesAtNode[i][j]) nPreviousParticles += locallen - for k in 1:locallen - push!(model.ParticlePool, [deepcopy(model.ParticlesAtNode[i][j][k][3]), i, j, exp(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[1])*model.ParticlesAtNode[i][j][k][1]]) + @threads for k in 1:locallen + + Upart=model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u + # newodeint=init(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.t,[deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[1]), deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[2]), deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[3]), deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[4]), deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[5]), deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[6])]) + # println(newodeint) + # println() + + z_init = ParticleDefaults(Upart[1],Upart[2],Upart[3],Upart[4],Upart[5],Upart[6]) + newpart=InitParticleInstance(model.ODEsystem,z_init,model.ODEsettings,(i,j),false,true) + push!(model.ParticlePool, [newpart, i, j, exp(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[1])*model.ParticlesAtNode[i][j][k][1]]) + + #newpart2=[deepcopy(model.ParticlesAtNode[i][j][k][3]), i, j, exp(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[1])*model.ParticlesAtNode[i][j][k][1]] + #push!(model.ParticlePool, newpart2) end end @@ -300,7 +346,7 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb #print("mean energy after remesh ", mean_of_state(model), "\n") tick!(model.clock, Δt) - @printf(" mean energy %.6f ", mean_of_state(model)) + #@printf(" mean energy %.6f ", mean_of_state(model)) end diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index d144764..8efbbb4 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -120,7 +120,9 @@ function advance!(PI::AbstractParticleInstance, if PI.on #& ~PI.boundary # if Particle is on and not boundary try - step!(PI.ODEIntegrator, DT, true) + PI.ODEIntegrator.u[4] += DT*PI.ODEIntegrator.u[2] + PI.ODEIntegrator.u[5] += DT*PI.ODEIntegrator.u[3] + # step!(PI.ODEIntegrator, DT, true) catch e @printf "error on advancing ODE:\n" print("- time after fail $(PI.ODEIntegrator.t)\n ") @@ -168,6 +170,10 @@ function advance!(PI::AbstractParticleInstance, @info "position or Energy is nan, reset" @info PI.position_ij @show PI + @info PI.ODEIntegrator.uprev + @info PI.ODEIntegrator.uprev2 + + test.test t_end = t_start + DT winds_start = convert( Tuple{Float64,Float64}, diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index 1f2557c..c65fb87 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -16,6 +16,10 @@ using Statistics import Plots as plt +using DataFrames, CSV +using Random, Distributions +using Dates + #using ThreadsX function mean_of_state(model::Abstract2DModel) @@ -42,6 +46,35 @@ function plot_state_and_error_points(wave_simulation, gn) ylims=(gn.ymin, gn.ymax)) |> display end +function write_particles_to_csv(wave_model) + sec=string(Int64(floor((wave_model.clock.time)/60))) + dec=string(Int64(floor(10*(wave_model.clock.time/60-floor((wave_model.clock.time)/60))))) + save_path = wave_model.plot_savepath + + nParticles = wave_model.n_particles_launch + @info wave_model.clock.time/60 + + parts = wave_model.ParticleCollection[(end-nParticles+1):end] + + logE = zeros(nParticles) + cx = zeros(nParticles) + cy = zeros(nParticles) + x = zeros(nParticles) + y = zeros(nParticles) + for i in 1:nParticles + logE[i] = parts[i].ODEIntegrator[1] + cx[i] = parts[i].ODEIntegrator[2] + cy[i] = parts[i].ODEIntegrator[3] + x[i] = parts[i].ODEIntegrator[4] + y[i] = parts[i].ODEIntegrator[5] + end + + data = DataFrame(id=1:nParticles, logE = logE, cx = cx, cy = cy, x = x, y = y) + data2 = Tables.table(transpose(wave_model.State[:, :, 1])) + CSV.write(save_path*"/data/particles_"*sec*","*dec*".csv", data) + CSV.write(save_path*"/data/mesh_values_"*sec*","*dec*".csv", data2) + end + function get_tot_energy_domain(wave_simulation) return sum(wave_simulation.model.State[:,:,1]) end @@ -54,12 +87,50 @@ Needs time_step! to be defined for the model, and push_state_to_storage! to be d function run!(sim; store=false, pickup=false, cash_store=false, debug=false) save_path = sim.model.plot_savepath + if sim.model.save_particles + save_path = sim.model.plot_savepath + filename = save_path*"/data/simu_infos.csv" + + Nx = sim.model.grid.Nx + Ny = sim.model.grid.Ny + xmin = sim.model.grid.xmin + xmax = sim.model.grid.xmax + ymin = sim.model.grid.ymin + ymax = sim.model.grid.ymax + lne_source = sim.model.ODEdefaults.lne + c_x_source = sim.model.ODEdefaults.c̄_x + c_y_source = sim.model.ODEdefaults.c̄_y + x_source = sim.model.ODEdefaults.x + y_source = sim.model.ODEdefaults.y + angular_spread_source = sim.model.ODEdefaults.angular_σ + Δt = sim.Δt + stop_time = sim.stop_time + + data = DataFrame(Nx=Nx, Ny=Ny, xmin=xmin, + xmax=xmax, ymin=ymin, ymax=ymax, + lne_source=lne_source, c_x_source=c_x_source, + c_y_source=c_y_source, x_source=x_source,y_source=y_source, + angular_spread_source=angular_spread_source, + Δt=Δt, stop_time=stop_time) + CSV.write(filename, data) + + filename2 = save_path*"/data/sigma.csv" + + covariance_init = sim.model.proba_covariance_init + data2 = DataFrame(covariance_init, :auto) + CSV.write(filename2, data2) + end + start_time_step = time_ns() if !(sim.initialized) # execute initialization step initialize_simulation!(sim) end + if sim.model.save_particles && length(sim.model.ParticleCollection) > 0 + write_particles_to_csv(sim.model) + end + #sim.running = true sim.run_wall_time = 0.0 @@ -95,9 +166,56 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) #reset State sim.model.State .= 0.0 # do time step - + + #launch new batch of particles from cyclic launch + if length(sim.model.PointSourceList) > 0 + for k in 1:length(sim.model.PointSourceList) + currentParticle = sim.model.PointSourceList[k].particleLaunch + currentFirstTimeLaunched = sim.model.PointSourceList[k].firstTimeLaunched + period = sqrt(sim.model.grid.dx*sim.model.grid.dy + / + (currentParticle.c̄_x^2+currentParticle.c̄_y^2)) + + t = sim.model.ParticleCollection[end].ODEIntegrator.t + #computing how many batches of particles have to be launched + timePrevLaunch = t >= currentFirstTimeLaunched ? t - (t - currentFirstTimeLaunched)%period : -1.0 + nBatch = 0 + + while timePrevLaunch > sim.model.ParticleCollection[end].ODEIntegrator.t - sim.Δt + nBatch+=1 + timePrevLaunch-=period + end + + for nB in 1:nBatch + i = Int64(floor((sim.model.PointSourceList[k].particleLaunch.x - sim.model.grid.xmin) / sim.model.grid.dx)) + 1 + j = Int64(floor((sim.model.PointSourceList[k].particleLaunch.y - sim.model.grid.ymin) / sim.model.grid.dy)) + 1 + n_part = sim.model.n_particles_launch + + defaults_temp = deepcopy(sim.model.PointSourceList[k].particleLaunch) + defaults_temp.lne -= log(n_part) + basePart = SeedParticle(sim.model.State, + (i,j), sim.model.ODEsystem, defaults_temp, + sim.model.ODEsettings,gridnotes, sim.model.winds, + sim.model.ODEsettings.timestep, sim.model.boundary, + sim.model.periodic_boundary) + for _ in 1:n_part + delta_phi = rand() * defaults_temp.angular_σ - 0.5*defaults_temp.angular_σ + c_x = defaults_temp.c̄_x * cos(delta_phi) - defaults_temp.c̄_y * sin(delta_phi) + c_y = defaults_temp.c̄_x * sin(delta_phi) + defaults_temp.c̄_y * cos(delta_phi) + push!(sim.model.ParticleCollection, deepcopy(basePart)) + sim.model.ParticleCollection[end].ODEIntegrator.u[2] = c_x + sim.model.ParticleCollection[end].ODEIntegrator.u[3] = c_y + sim.model.ParticleCollection[end].ODEIntegrator.uprev[2] = c_x + sim.model.ParticleCollection[end].ODEIntegrator.uprev[3] = c_y + sim.model.ParticleCollection[end].ODEIntegrator.uprev2[2] = c_x + sim.model.ParticleCollection[end].ODEIntegrator.uprev2[3] = c_y + end + end + #@info "nBatch = ", nBatch + end + end time_step!(sim.model, sim.Δt, debug=debug) - + if debug & (length(sim.model.FailedCollection) > 0) @info "debug mode:" @info "found failed particles" @@ -128,14 +246,12 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) end sim.running = sim.stop_time >= sim.model.clock.time ? true : false - @info sim.model.clock if sim.model.plot_steps - @info "plot" plot_state_and_error_points(sim, gridnotes) - plt.savefig(joinpath([save_path, "energy_plot_no_spread_"*string(Int64(floor((sim.model.clock.time)/60)))*".png"])) - else - @info "not plot" + sec=string(Int64(floor((sim.model.clock.time)/60))) + dec=string(Int64(floor(10*(sim.model.clock.time/60-floor((sim.model.clock.time)/60))))) + plt.savefig(joinpath([save_path*"/plots/", "energy_plot_no_spread_"*sec*","*dec*".png"])) end end @@ -271,21 +387,77 @@ function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose:: j = Int64(floor((defaults.y - model.grid.ymin) / model.grid.dy)) + 1 gridnotes = TwoDGridNotes(model.grid) if model.angular_spreading_type == "nonparametric" - # if "nonparametric" is used, initialize a bigger number of particles at the original perturbation - n_part = model.n_particles_launch - for _ in 1:n_part - defaults_temp = deepcopy(defaults) - delta_phi = rand() * defaults_temp.angular_σ - 0.5*defaults_temp.angular_σ - c_x = defaults_temp.c̄_x * cos(delta_phi) - defaults_temp.c̄_y * sin(delta_phi) - c_y = defaults_temp.c̄_x * sin(delta_phi) + defaults_temp.c̄_y * cos(delta_phi) - defaults_temp.lne += -log(n_part) - defaults_temp.c̄_x = c_x - defaults_temp.c̄_y = c_y - push!(ParticleCollection, SeedParticle(model.State, - (i,j), model.ODEsystem, defaults_temp, - model.ODEsettings,gridnotes, model.winds, - model.ODEsettings.timestep, model.boundary, - model.periodic_boundary)) + if sum(model.proba_covariance_init)==4e-50 + # if "nonparametric" is used, initialize a bigger number of particles at the original perturbation + n_part = model.n_particles_launch + for _ in 1:n_part + defaults_temp = deepcopy(defaults) + delta_phi = rand() * defaults_temp.angular_σ - 0.5*defaults_temp.angular_σ + c_x = defaults_temp.c̄_x * cos(delta_phi) - defaults_temp.c̄_y * sin(delta_phi) + c_y = defaults_temp.c̄_x * sin(delta_phi) + defaults_temp.c̄_y * cos(delta_phi) + defaults_temp.lne += -log(n_part) + defaults_temp.c̄_x = c_x + defaults_temp.c̄_y = c_y + push!(ParticleCollection, SeedParticle(model.State, + (i,j), model.ODEsystem, defaults_temp, + model.ODEsettings,gridnotes, model.winds, + model.ODEsettings.timestep, model.boundary, + model.periodic_boundary)) + end + else + n_part = model.n_particles_launch + for _ in 1:n_part + defaults_temp = deepcopy(defaults) + mu = [defaults_temp.c̄_x, defaults_temp.c̄_y, defaults_temp.x, defaults_temp.y] + d = MvNormal(mu, model.proba_covariance_init) + real = rand(d,1) + # delta_phi = real[1] + # delta_phi < 0 ? delta_phi = - delta_phi : delta_phi = delta_phi + # delta_phi < 0.01 ? delta_phi+=1 : delta_phi +=0 + # c_x = (real[2]+1)*(defaults_temp.c̄_x * cos(delta_phi) - defaults_temp.c̄_y * sin(delta_phi)) + # c_y = (real[2]+1)*(defaults_temp.c̄_x * sin(delta_phi) + defaults_temp.c̄_y * cos(delta_phi)) + c_x = real[1] + c_y = real[2] + defaults_temp.lne += -log(n_part) + defaults_temp.c̄_x = c_x + defaults_temp.c̄_y = c_y + defaults_temp.x = real[3] + defaults_temp.y = real[4] + push!(ParticleCollection, SeedParticle(model.State, + (i,j), model.ODEsystem, defaults_temp, + model.ODEsettings,gridnotes, model.winds, + model.ODEsettings.timestep, model.boundary, + model.periodic_boundary)) + end + # for _ in 1:n_part + # temp_boucle = true + # while temp_boucle + # defaults_temp = deepcopy(defaults) + # mu = [defaults_temp.c̄_x, defaults_temp.c̄_y, defaults_temp.x, defaults_temp.y] + # d = MvNormal(mu, model.proba_covariance_init) + # real = rand(d,1) + # delta_phi = real[1] + # #delta_phi < 0 ? delta_phi = - delta_phi : delta_phi = delta_phi + # #delta_phi < 0.01 ? delta_phi+=1 : delta_phi +=0 + # #c_x = (real[2]+1)*(defaults_temp.c̄_x * cos(delta_phi) - defaults_temp.c̄_y * sin(delta_phi)) + # #c_y = (real[2]+1)*(defaults_temp.c̄_x * sin(delta_phi) + defaults_temp.c̄_y * cos(delta_phi)) + # c_x = real[1] + # c_y = real[2] + # defaults_temp.lne += -log(n_part) + # defaults_temp.c̄_x = c_x + # defaults_temp.c̄_y = c_y + # defaults_temp.x = real[3] + # defaults_temp.y = real[4] + # if c_x^2+c_y^2<=1 + # push!(ParticleCollection, SeedParticle(model.State, + # (i,j), model.ODEsystem, defaults_temp, + # model.ODEsettings,gridnotes, model.winds, + # model.ODEsettings.timestep, model.boundary, + # model.periodic_boundary)) + # temp_boucle = false + # end + # end + # end end else push!(ParticleCollection, SeedParticle(model.State, @@ -306,6 +478,31 @@ function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose:: model.periodic_boundary)) end end + + if length(model.PointSourceList) != 0 + @info "launching cyclic point source particles" + for k in 1:length(model.PointSourceList) + if model.PointSourceList[k].firstTimeLaunched != 0.0 + i = Int64(floor((model.PointSourceList[k].particleLaunch.x - model.grid.xmin) / model.grid.dx)) + 1 + j = Int64(floor((model.PointSourceList[k].particleLaunch.y - model.grid.ymin) / model.grid.dy)) + 1 + n_part = model.n_particles_launch + for _ in 1:n_part + defaults_temp = deepcopy(model.PointSourceList[k].particleLaunch) + delta_phi = rand() * defaults_temp.angular_σ - 0.5*defaults_temp.angular_σ + c_x = defaults_temp.c̄_x * cos(delta_phi) - defaults_temp.c̄_y * sin(delta_phi) + c_y = defaults_temp.c̄_x * sin(delta_phi) + defaults_temp.c̄_y * cos(delta_phi) + defaults_temp.lne += -log(n_part) + defaults_temp.c̄_x = c_x + defaults_temp.c̄_y = c_y + push!(ParticleCollection, SeedParticle(model.State, + (i,j), model.ODEsystem, defaults_temp, + model.ODEsettings,gridnotes, model.winds, + model.ODEsettings.timestep, model.boundary, + model.periodic_boundary)) + end + end + end + end nothing end diff --git a/tests/test_case_1.jl b/tests/test_case_1.jl new file mode 100644 index 0000000..9302e5d --- /dev/null +++ b/tests/test_case_1.jl @@ -0,0 +1,117 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +save_path = "plots/tests/paper/test_case_1/" +mkpath(save_path) + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(22.5e4, 151, 22.5e4, 151) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1, 0.0, 22, 112500, 15000., π) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/tests/paper/test_case_1/v2_pi", + angular_spreading_type="nonparametric", + proba_covariance_init = [1e-50 0 0 0; + 0 1e-50 0 0; + 0 0 1e-50 0 + 0 0 0 1e-50], + n_particles_launch=150000 + ) + +wave_simulation = Simulation(wave_model, Δt=0.75minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2.jl b/tests/test_case_2.jl new file mode 100644 index 0000000..f3a2ccd --- /dev/null +++ b/tests/test_case_2.jl @@ -0,0 +1,117 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +save_path = "plots/tests/paper/test_case_3/" +mkpath(save_path) + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/tests/paper/test_case_3/v2_half_cell_batch1", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=1000000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) From e58e2460096eda7a560579b4292aabb4ded4f605 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Mon, 28 Apr 2025 15:47:58 +0200 Subject: [PATCH 13/37] Creating the SIR analysis file --- SIR_analysis.jl | 1316 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1316 insertions(+) create mode 100644 SIR_analysis.jl diff --git a/SIR_analysis.jl b/SIR_analysis.jl new file mode 100644 index 0000000..6902aa7 --- /dev/null +++ b/SIR_analysis.jl @@ -0,0 +1,1316 @@ +using DataFrames, DelimitedFiles +using LinearAlgebra +import Statistics as Stc +using GLM +using LaTeXStrings +# import Plots as plt +using Colors +using Random, Distributions +using PlotlyJS +using SpecialFunctions +import PlotlyBase: make_subplots +using Pkg +Pkg.add(url="https://github.com/cossio/TruncatedNormal.jl") +import TruncatedNormal as tn + +## Defining useful functions + +function gaussD(mu, sigma, x1) + value = 1/((2*pi)^0.5 * sigma^0.5) * exp(-0.5*(x1-mu)*sigma^(-1)*(x1-mu)) + return value +end + +function print_mat(M) + a = size(M)[1] + b = size(M)[2] + print("[") + for i in 1:a + if i != 1 println() end + print(M[i,1]) + for j in 2:b + print(", ") + print(M[i,j]) + end + end + println("]") +end + +function gaussMultiD(mu, sigma, sigma1, x1) + dim = length(mu) + value = 1/((2*pi)^(dim/2) * det(sigma)^0.5) * exp(-0.5*transpose(x1-mu)*sigma1*(x1-mu)) + return value +end + +function spectrum_at_point(T, PartStates, xyPoint, sigma, kxrange, kyrange, nkX, nkY) + kxs = (0:(nkX-1))/nkX*(kxrange[2]-kxrange[1]).+kxrange[1] + kys = (0:(nkY-1))/nkY*(kyrange[2]-kyrange[1]).+kyrange[1] + + sigma1 = inv(sigma) + influence_radius_2 = sqrt(sigma[1,1])^2+sqrt(sigma[2,2])^2 + + particles = PartStates[T,"particleList"] + nPart = (size(particles))[1] + + result = zeros(nkX,nkY) + + for i in 1:nPart + if (particles[i,"x"]-xyPoint[1])^2+(particles[i,"y"]-xyPoint[2])^2 < influence_radius_2*1.5 + for x in 1:nkX + for y in 1:nkY + result[x,y] += gaussMultiD([xyPoint[1],xyPoint[2], kxs[x], kys[y]], sigma, sigma1, [particles[i,"x"],particles[i,"y"],particles[i,"cx"],particles[i,"cy"]]) + end + end + end + end + return result +end + +function compute_spectrum_parameters(T, PartStates, xyPoint, sigma, aggregation_type) + all_particles = PartStates[T,"particleList"][:,["cx","cy","x","y"]] + + influence_radius = (sqrt(sigma[1,1])^2+sqrt(sigma[2,2])^2) + sigma = [influence_radius 0; 0 influence_radius] + sigma1 = inv(sigma) + result = DataFrame(cx=[],cy=[],x=[],y=[]) + weights = [] + + for i in 1:size(all_particles)[1] + temp_pos = Vector(all_particles[i,["x","y"]]) + dist = (temp_pos-xyPoint)[1]^2+(temp_pos-xyPoint)[2]^2 + if dist < influence_radius* (10)^2 + append!(result,DataFrame(all_particles[i,:])) + if aggregation_type == "gauss" + append!(weights, gaussMultiD(temp_pos, sigma, sigma1, xyPoint)) + elseif aggregation_type == "const" + append!(weights, 1) + elseif aggregation_type == "lin" + if abs(temp_pos[1]-xyPoint[1]) <= sqrt(sigma[1,1]) && abs(temp_pos[2]-xyPoint[2]) <= sqrt(sigma[2,2]) + append!(weights,(abs(temp_pos[1]-xyPoint[1])/sqrt(sigma[1,1])*abs(temp_pos[2]-xyPoint[2])/sqrt(sigma[2,2]))) + else + append!(weights, 0) + end + end + end + end + + if length(weights) == 0 + return [0 0; 0 0], 0 + end + sumWeights=sum(weights) + weights=weights./sumWeights + cBar_cx = sum(Matrix(weights.*result[:,["cx"]])) + cBar_cy = sum(Matrix(weights.*result[:,["cy"]])) + + cov_cxcx = 1/(1-sum(weights.^2))*sum(weights.*(Matrix(result[:,["cx"]]).-cBar_cx).^2) + cov_cycy = 1/(1-sum(weights.^2))*sum(weights.*(Matrix(result[:,["cy"]]).-cBar_cy).^2) + cov_cxcy = 1/(1-sum(weights.^2))*sum(weights.*(Matrix(result[:,["cx"]]).-cBar_cx).*(Matrix(result[:,["cy"]]).-cBar_cy)) + result_cov = [cov_cxcx cov_cxcy; cov_cxcy cov_cycy] + + return result_cov, sumWeights +end + +function compute_derivative(y, t, step) + results = zeros(length(t)-2*step) + times = t[(step+1):(end-step)] + for i in 1:(length(t)-2*step) + results[i] = (y[i+2*step]-y[i])/(t[i+2*step]-t[i]) + end + return times, results +end + +function spectrum_parameters_at_point(T, PartStates, xyPoint, influenceZone) + peak_speeds = Matrix{} +end + +function peak_spectrum(T, PartStates, xyPoint, sigma, sigma1) + particles = PartStates[T,"particleList"] + nPart = (size(particles))[1] + influence_radius_2 = (sigma[1,1])+(sigma[2,2]) + + value = [0; 0] + weights = 0 + for i in 1:nPart + if (particles[i,"x"]-xyPoint[1])^2+(particles[i,"y"]-xyPoint[2])^2 < influence_radius_2*(25)^2 + local_weight = gaussMultiD(xyPoint, sigma, sigma1, [particles[i, "x"]; particles[i, "y"]]) + value += [particles[i,"cx"]; particles[i,"cy"]] * local_weight + weights += local_weight + end + end + if weights == 0 + weights = 1 + end + return value/weights +end + +function find_geometrical_center(T, PartStates) + particles = PartStates[T,"particleList"] + return [Stc.mean(particles[:,"x"]), Stc.mean(particles[:,"y"])] +end + +function unit_dec(a) + unit=string(Int64(floor((a)))) + dec=string(Int64(floor(10*(a-floor((a)))))) + return unit*","*dec +end + +function plot_state_and_error_points(State, xs, ys, cRange, widthPlot, heightPlot; showTitle = true) + custom_color_scale = [(0.0,"rgb(229, 229, 229)"),(0.3,"rgb(255, 230, 44)"), (1.0, "rgb(255, 0, 0)")] + + traceq1 = heatmap(x=xs, y=ys, z=Matrix(State[:, :]), colorscale=custom_color_scale + ,colorbar=attr(tickformat=".1e",cmin = cRange[1], cmax = cRange[2]) + ,zmin = cRange[1], zmax = cRange[2] + ) + + LatexFont = attr(color="black",family="Computer Modern",size=22) + + if showTitle + q1=plot(traceq1, + Layout( + title=attr(text="\$ \\Large{\\text{Energy distribution in space}}\$", + x = 0.5, + xanchor="center", + font=attr(color="black")), + font=LatexFont, + width=widthPlot, height=heightPlot, + xaxis=attr(title=attr(text="\$\\Large{\\text{x position in } km}\$",font=attr(color="black"))), + yaxis=attr(title=attr(text="\$\\Large{\\text{y position in } km}\$",font=attr(color="black")),scaleanchor="x")) + ) + else + q1=plot(traceq1, + Layout( + font=LatexFont, + width=widthPlot, height=heightPlot, + xaxis=attr(title=attr(text="\$\\Large{\\text{x position in } km}\$",font=attr(color="black"))), + yaxis=attr(title=attr(text="\$\\Large{\\text{y position in } km}\$",font=attr(color="black")),scaleanchor="x")) + ) + end + return q1 +end + +function compute_translated_gaussian(mu_init, sigma_init, M, time) + translated_mu = M(time)*mu_init + translated_sigma = M(time)*transpose(sigma_init)*transpose(M(time)) + return translated_mu, translated_sigma +end + +function pearson(data, predicted) + meanValue = Stc.mean(data) + return 1-sum((data-predicted).^2)/sum((data.-meanValue).^2) +end + +## Reading the data +localpath = pwd() + +# parentPath = localpath * "/plots/tests/paper/test_case_1/v2_pi" +# parentPath = localpath * "/plots/tests/paper/test_case_2_local/v2_pi_4" +# parentPath = localpath * "/plots/tests/paper/test_case_2/v2_pi_4" +# parentPath = localpath * "/plots/tests/paper/test_case_3/v2_half_cell" +# parentPath = localpath * "/plots/tests/paper/test_case_3/v2_half_cell" +# parentPath = localpath * "/plots/tests/paper/test_case_2/v2_pi_4_operationnel" +# parentPath = localpath * "/plots/tests/paper/test_debug/v2_half_cell" + +println("------------ Reading the data from : "* parentPath * " ------------") +path = parentPath*"/data/simu_infos.csv" +path3 = parentPath*"/data/sigma.csv" +data, header = readdlm(path, ',', header=true) +data3, header3 = readdlm(path3, ',', header=true) + +simu_infos = DataFrame(data, vec(header)) +init_sigma_df = DataFrame(data3, vec(header3)) + +init_sigma = Matrix(init_sigma_df) +Nx = simu_infos.Nx[1] +Ny = simu_infos.Ny[1] +xmin = simu_infos.xmin[1] +xmax = simu_infos.xmax[1] +ymin = simu_infos.ymin[1] +ymax = simu_infos.ymax[1] +lne_source = simu_infos.lne_source[1] +c_x_source = simu_infos.c_x_source[1] +c_y_source = simu_infos.c_y_source[1] +init_mu_C = [c_x_source, c_y_source] +x_source = simu_infos.x_source[1] +y_source = simu_infos.y_source[1] +init_mu_X = [x_source,y_source] +angular_spread_source = simu_infos.angular_spread_source[1] +Δt = simu_infos.Δt[1] +stop_time = simu_infos.stop_time[1] + +nTimes = Int64(ceil(stop_time/Δt))+1 + +# times = (1:(nTimes))*Δt +times = (0:(nTimes-1))*Δt +timesMinutes = times/60 + +timesMinutesString = unit_dec.(timesMinutes) + +ParticleStates = DataFrame([[],[]],["times", "particleList"]) +MeshState = DataFrame([[],[]],["times", "mesh_state"]) + +for i in 1:nTimes + path1 = parentPath*"/data/particles_"*timesMinutesString[i]*".csv" + path2 = parentPath*"/data/mesh_values_"*timesMinutesString[i]*".csv" + data1, header1 = readdlm(path1, ',', header=true) + data2, header2 = readdlm(path2, ',', header=true) + + read_df1 = DataFrame(data1, vec(header1)) + read_df2 = DataFrame(data2, vec(header2)) + + temp_df1 = DataFrame([[timesMinutes[i]], [read_df1]], ["times", "particleList"]) + temp_df2 = DataFrame([[timesMinutes[i]], [read_df2]], ["times", "mesh_state"]) + append!(ParticleStates, temp_df1) + append!(MeshState, temp_df2) +end + +## Building the spectrum at different points and different times + +nParticles = size(ParticleStates[1,"particleList"])[1] + +nkX = 15 +nkY = 15 + +kxscale = [-10, 30] +kyscale = [-10, 30] + +alpha = 5 +alpha = alpha /180 * pi +rotMatPos = [cos(alpha) -sin(alpha); sin(alpha) cos(alpha)] +rotMatNeg = [cos(-alpha) -sin(-alpha); sin(-alpha) cos(-alpha)] + +kxs = (0:(nkX-1))/nkX*(kxscale[2]-kxscale[1]).+kxscale[1] +kys = (0:(nkY-1))/nkY*(kyscale[2]-kyscale[1]).+kyscale[1] + +sigma_x = (xmax-xmin)/(Nx-1) +sigma_y = (ymax-ymin)/(Ny-1) +sigma_kx = (kxscale[2]-kxscale[1])/nkX +sigma_ky = (kyscale[2]-kyscale[1])/nkY + +kernel = [sigma_x^2 0 0 0; + 0 sigma_y^2 0 0; + 0 0 sigma_kx^2 0; + 0 0 0 sigma_ky^2] + +sdx_end = sqrt(Stc.var(ParticleStates[nTimes, "particleList"][:,"x"])) +sdy_end = sqrt(Stc.var(ParticleStates[nTimes, "particleList"][:,"y"])) + +xyCenter_1 = find_geometrical_center(1, ParticleStates) +xyCenter_2 = find_geometrical_center(Int64(floor(nTimes/2)), ParticleStates) +xyCenter_end = find_geometrical_center(nTimes, ParticleStates) +xy_right = rotMatNeg * xyCenter_end +xy_left = rotMatPos * xyCenter_end +xy_forw = xyCenter_end + 1 * [sdx_end,sdy_end] +xy_back = xyCenter_end - 1 * [sdx_end,sdy_end] +println() +println("------------------------------------------------") +println(" POSITIONS :") +println() + +println("Center at t=0 : (x,y) = ("*string(xyCenter_1[1])*","*string(xyCenter_1[2])*")") +println("Center at t="*timesMinutesString[nTimes]*" : (x,y) = ("*string(xyCenter_end[1])*","*string(xyCenter_end[2])*")") +println("Right at t="*timesMinutesString[nTimes]*" : (x,y) = ("*string(xy_right[1])*","*string(xy_right[2])*")") +println("Left at t="*timesMinutesString[nTimes]*" : (x,y) = ("*string(xy_left[1])*","*string(xy_left[2])*")") +println("Forward at t="*timesMinutesString[nTimes]*" : (x,y) = ("*string(xy_forw[1])*","*string(xy_forw[2])*")") +println("Backward at t="*timesMinutesString[nTimes]*" : (x,y) = ("*string(xy_back[1])*","*string(xy_back[2])*")") + +compute_spectra_bool = false + +if compute_spectra_bool + + println() + println("------------------------------------------------") + println(" COMPUTING SPECTRA :") + println() + + spectrum_1 = spectrum_at_point(1, ParticleStates, xyCenter_1, kernel, kxscale, kyscale, nkX, nkY) + println("Spectrum 1 over") + spectrum_2 = spectrum_at_point(Int64(floor(nTimes/2)), ParticleStates, xyCenter_2, kernel, kxscale, kyscale, nkX, nkY) + println("Spectrum 1 over") + spectrum_3 = spectrum_at_point(nTimes, ParticleStates, xyCenter_end, kernel, kxscale, kyscale, nkX, nkY) + println("Spectrum 2 over") + #spectrum_right = spectrum_at_point(nTimes, ParticleStates, xy_right, kernel, kxscale, kyscale, nkX, nkY) + spectrum_end = zeros(nkX, nkY) + spectrum_right = zeros(nkX, nkY) + println("Spectrum 3 over") + # spectrum_left = spectrum_at_point(nTimes, ParticleStates, xy_left, kernel, kxscale, kyscale, nkX, nkY) + spectrum_left = zeros(nkX, nkY) + println("Spectrum 4 over") + spectrum_forw = spectrum_at_point(nTimes, ParticleStates, xy_forw, kernel, kxscale, kyscale, nkX, nkY) + println("Spectrum 5 over") + spectrum_back = spectrum_at_point(nTimes, ParticleStates, xy_back, kernel, kxscale, kyscale, nkX, nkY) + println("Spectrum 6 over") + println() + + # FIRST PLOT + axis_template = attr(range = [-10,30], autorange = false, + showgrid = false, zeroline = false, + linecolor = "black", showticklabels = true, + ticks = "" ) + + sp1_trace = heatmap(x=kxs, y=kys, z=spectrum_1) + sp1_trace2 = scatter(x=[0, 0],y=[-20, 40], line=attr(color="black", width=3), showticklabels = false, ticks = "", name="") + sp1_trace3 = scatter(y=[0, 0],x=[-20, 40], line=attr(color="black", width=3), showticklabels = false, ticks = "", name="") + sp1 = plot([sp1_trace, sp1_trace2, sp1_trace3], Layout( + legend=:none, + title = "Energy Spectrum (in velocity) at t=0", + xaxis=axis_template, + yaxis=axis_template, + yaxis_title="c_y", + xaxis_title="c_x",width=1000, height=1000, + font=attr(size=28))) + + # SECOND PLOT + axis_template = attr(range = [-10,30], autorange = false, + showgrid = false, zeroline = false, + linecolor = "black", showticklabels = true, + ticks = "" ) + + sp2_trace = heatmap(x=kxs, y=kys, z=spectrum_2) + sp2_trace2 = scatter(x=[0, 0],y=[-20, 40], line=attr(color="black", width=3), showticklabels = false, ticks = "", name="") + sp2_trace3 = scatter(y=[0, 0],x=[-20, 40], line=attr(color="black", width=3), showticklabels = false, ticks = "", name="") + sp2 = plot([sp2_trace, sp2_trace2, sp2_trace3], Layout( + legend=:none, + title = "Energy Spectrum (in velocity) at t=0", + xaxis=axis_template, + yaxis=axis_template, + yaxis_title="c_y", + xaxis_title="c_x",width=1000, height=1000, + font=attr(size=28))) + + # THIRD PLOT + axis_template = attr(range = [-10,30], autorange = false, + showgrid = false, zeroline = false, + linecolor = "black", showticklabels = true, + ticks = "" ) + + sp3_trace = heatmap(x=kxs, y=kys, z=spectrum_3) + sp3_trace2 = scatter(x=[0, 0],y=[-20, 40], line=attr(color="black", width=3), showticklabels = false, ticks = "", name="") + sp3_trace3 = scatter(y=[0, 0],x=[-20, 40], line=attr(color="black", width=3), showticklabels = false, ticks = "", name="") + sp3 = plot([sp3_trace, sp3_trace2, sp3_trace3], Layout( + legend=:none, + title = "Energy Spectrum (in velocity) at t=0", + xaxis=axis_template, + yaxis=axis_template, + yaxis_title="c_y", + xaxis_title="c_x",width=1000, height=1000, + font=attr(size=28))) + + # NEXT PLOTS + p2 = plt.heatmap(kxs, kys, spectrum_end, aspect_ratio=:equal, size=(2160, 2500)) + plt.plot!(legend=:none, + title = "Energy Spectrum in velocity at t="*timesMinutesString[nTimes], + ylabel="c_y", + xlabel="c_x") + + p3 = plt.heatmap(kxs, kys, spectrum_right, aspect_ratio=:equal, size=(2160, 2500)) + plt.plot!(legend=:none, + title = "Energy Spectrum in velocity at t="*timesMinutesString[nTimes], + ylabel="c_y", + xlabel="c_x") + + p4 = plt.heatmap(kxs, kys, spectrum_left, aspect_ratio=:equal, size=(2160, 2500)) + plt.plot!(legend=:none, + title = "Energy Spectrum in velocity at t="*timesMinutesString[nTimes], + ylabel="c_y", + xlabel="c_x") + + p5 = plt.heatmap(kxs, kys, spectrum_forw, aspect_ratio=:equal, size=(2160, 2500)) + plt.plot!(legend=:none, + title = "Energy Spectrum in velocity at t="*timesMinutesString[nTimes], + ylabel="c_y", + xlabel="c_x") + + p6 = plt.heatmap(kxs, kys, spectrum_back, aspect_ratio=:equal, size=(2160, 2500)) + plt.plot!(legend=:none, + title = "Energy Spectrum in velocity at t="*timesMinutesString[nTimes], + ylabel="c_y", + xlabel="c_x") + + + max_speed_id = argmax(spectrum_1) + max_speed = [kxs[max_speed_id[1]],kys[max_speed_id[2]]] + + proba_spectrum_1 = spectrum_1 / sum(spectrum_1) + proba_spectrum_1[max_speed_id[1],max_speed_id[2]] += 1-sum(proba_spectrum_1) +end + +println("DONE") + + +xs = (0:(Nx-1))./(Nx-1)*(xmax-xmin).+xmin +ys = (0:(Ny-1))./(Ny-1)*(ymax-ymin).+ymin + +# Plotting test case 1 plots + +plot_test_case_1 = false + +if plot_test_case_1 + plotting_times = [2, Int64(floor(size(MeshState)[1]/2))+1, size(MeshState)[1]] + + halfMeshStates = DataFrame([[],[]], ["times", "mesh_state"]) + + + yid_to_plot = 1:(size(MeshState[1, "mesh_state"])[1]) + xid_to_plot = 1:Int64(floor(size(MeshState[1, "mesh_state"])[1]/2)) + for i in 1:length(plotting_times) + values = MeshState[plotting_times[i], "mesh_state"] + values = values[xid_to_plot,yid_to_plot] + df = DataFrame([[MeshState[plotting_times[i],"times"]], [values]], ["times", "mesh_state"]) + append!(halfMeshStates, df) + end + + cRange = [0, maximum(Matrix(halfMeshStates[2, "mesh_state"]))] + + tc1_1 = plot_state_and_error_points(halfMeshStates[1, "mesh_state"], xs[xid_to_plot]./1000, ys[yid_to_plot]./1000, cRange, 1130, 573) + tc1_2 = plot_state_and_error_points(halfMeshStates[2, "mesh_state"], xs[xid_to_plot]./1000, ys[yid_to_plot]./1000, cRange, 1130, 573) + tc1_3 = plot_state_and_error_points(halfMeshStates[3, "mesh_state"], xs[xid_to_plot]./1000, ys[yid_to_plot]./1000, cRange, 1130, 573) + + save_plots = true + if save_plots + savefig(tc1_1,"test_case_1_t1.html") + savefig(tc1_2,"test_case_1_t2.html") + savefig(tc1_3,"test_case_1_t3.html") + println("Plotting times for the test case 1 energy distribution : "*string(MeshState[plotting_times[1], "times"])*", "*string(MeshState[plotting_times[2], "times"])*", "*string(MeshState[plotting_times[3], "times"])) + end + + # Plotting the energy decay rate + + axis_template = attr(autorange = true, + showgrid = true, zeroline = false, + linecolor = "black", showticklabels = true, + ticks = "" ) + + LatexFont = attr(color="black",family="Computer Modern",size=22) + + ed_layout = Layout(yaxis_type="log",xaxis_type="log", + title=attr(text="Energy density evolution with distance",font=LatexFont) + ,width=800, height=800 + ,xaxis_title=L"\Large{\text{distance in } km}" + ,yaxis_title=L"\Large{\text{Energy density (arbitrary units)}}" + ,legend=attr(borderwidth=1,x=0.1, y=0.4,font=LatexFont) + ,font=LatexFont + ,xaxis=axis_template + ,yaxis=axis_template + ,margin=attr(l=90,r=80,t=80,b=80) + ,template="simple_white") + + initPos = [x_source; y_source] + + argmaxValues = [argmax(transpose(Matrix(MeshState[i,"mesh_state"][:,:]))) for i in 2:(size(MeshState)[1])] + max_energy = [MeshState[i,"mesh_state"][argmaxValues[i-1][2],argmaxValues[i-1][1]] for i in 2:(size(MeshState)[1])] + maxPos = [[xmin.+(argmaxValues[i][1]-1) .* sigma_x; ymin.+(argmaxValues[i][2]-1) .* sigma_y] for i in 1:length(argmaxValues)] + maxDist = [sqrt((maxPos[i][1]-x_source)^2+(maxPos[i][2]-y_source)^2) for i in 1:length(maxPos)] + + coeff = 300 + perfect_1_r = [coeff/distance for distance in maxDist[12:end]] + + trace_energy_decay = scatter(x=maxDist./1000,y=max_energy, + name="\$\\text{Energy density}\$", + mode="markers" + ) + trace_perfect_1_r = scatter(x=maxDist[12:end]./1000,y=perfect_1_r, + name="\$\\frac{1}{r} \\text{ curve for reference}\$" + ) + tc1_ed = plot([trace_energy_decay, trace_perfect_1_r], ed_layout) + + if save_plots + savefig(tc1_ed,"test_case_1_energy_decay.html") + end + +end + +# Plotting test case 2 plots + +plot_test_case_2 = true + +if plot_test_case_2 + # Plotting the energy distribution + + plotting_times = [2, Int64(floor(size(MeshState)[1]/2))+2, size(MeshState)[1]] + + plotLog = false + colorbarDelay = 0 + if plotLog + cRange = [-10, maximum(Matrix(log.(MeshState[plotting_times[1]+colorbarDelay, "mesh_state"])))] + + tc2_1 = plot_state_and_error_points(log.(MeshState[plotting_times[1], "mesh_state"]), xs./1000, ys./1000, cRange, 1000, 885) + tc2_2 = plot_state_and_error_points(log.(MeshState[plotting_times[2], "mesh_state"]), xs./1000, ys./1000, cRange, 1000, 885) + tc2_3 = plot_state_and_error_points(log.(MeshState[plotting_times[3], "mesh_state"]), xs./1000, ys./1000, cRange, 1000, 885) + else + cRange = [0, maximum(Matrix(MeshState[plotting_times[2]+colorbarDelay, "mesh_state"]))] + + tc2_1 = plot_state_and_error_points(MeshState[plotting_times[1], "mesh_state"], xs./1000, ys./1000, cRange, 1000, 885; showTitle=false) + tc2_2 = plot_state_and_error_points(MeshState[plotting_times[2], "mesh_state"], xs./1000, ys./1000, cRange, 1000, 885; showTitle=false) + tc2_3 = plot_state_and_error_points(MeshState[plotting_times[3], "mesh_state"], xs./1000, ys./1000, cRange, 1000, 885; showTitle=false) + end + + save_plots = true + if save_plots + savefig(tc2_1,"test_case_2_t1.html") + savefig(tc2_2,"test_case_2_t2.html") + savefig(tc2_3,"test_case_2_t3.html") + println("Plotting times for the test case 2 energy distribution : "*string(MeshState[plotting_times[1], "times"])*", "*string(MeshState[plotting_times[2], "times"])*", "*string(MeshState[plotting_times[3], "times"])) + end + + # Plotting the two analysis plots + + xaxis_template = attr(#autorange = true, + showgrid = true, zeroline = false, + linecolor = "black", showticklabels = true, + ticks = "", + range=[xmin,xmax]./1000 + ) + + yaxis_template = attr(#autorange = true, + showgrid = true, zeroline = false, + linecolor = "black", showticklabels = true, + ticks = "", + range=[ymin,ymax]./1000 + ) + + LatexFont = attr(color="black",family="Computer Modern",size=22) + + ed_layout = Layout(#yaxis_type="log",xaxis_type="log", + title=attr(text="Particle positions at t=60sec",font=LatexFont) + ,width=1600, height=374 + ,xaxis_title=attr(text="\$\\Large{\\text{x position in } km}\$",font=attr(color="black")) + ,yaxis_title=attr(text="\$\\Large{\\text{y position in } km}\$",font=attr(color="black")) + ,legend=attr(borderwidth=1,x=0.1, y=0.4,font=LatexFont) + ,font=LatexFont + ,xaxis=xaxis_template + ,yaxis=yaxis_template + ,margin=attr(l=90,r=80,t=80,b=80) + ,template="simple_white") + + + cov_end = Stc.cov(Matrix(ParticleStates[1,"particleList"][:,["cx","cy","x","y"]])) + + # q1 = plot_state_and_error_points(MeshState[nTimes, "mesh_state"], xs, ys, xmin, xmax, ymin, ymax) + println("ici 1") + # particleSpeeds = sqrt.([sum((Matrix(ParticleStates[nTimes,"particleList"][:,["cx","cy"]]).^2)[i,:]) for i in 1:nParticles]) + particleSpeeds=zeros(nParticles) + plotting_time = Int64(floor(nTimes/2)) + for i in 1:nParticles + particleSpeeds[i] = sqrt(ParticleStates[plotting_time,"particleList"][:,"cx"][i]^2+ParticleStates[plotting_time,"particleList"][:,"cy"][i]^2) + end + println("ici 2") + particleXs = ParticleStates[plotting_time,"particleList"][:,"x"] + particleYs = ParticleStates[plotting_time,"particleList"][:,"y"] + M(t) = [Diagonal(ones(2)) Diagonal(zeros(2)); + t*Diagonal(ones(2)) Diagonal(ones(2))] + println("ici 3") + result_mu, result_sigma = compute_translated_gaussian([c_x_source, c_y_source, x_source, y_source], init_sigma, M, 60*timesMinutes[plotting_time]) + println("ici 4") + timeOfInterest = Int64(floor(nTimes/2)) + translated_mu_C = [c_x_source, c_y_source] + translated_mu_XY = [x_source, y_source] + timesMinutes[timeOfInterest]*60 * [c_x_source, c_y_source] + translated_sigma_XY = init_sigma[3:4,3:4] + (timesMinutes[timeOfInterest]*60)^2 * init_sigma[1:2,1:2] + translated_cross_cov = timesMinutes[timeOfInterest]*60 * init_sigma[1:2,1:2] + # translated_sigma_C = init_sigma[1:2,1:2] + # translated_cov_total=[translated_sigma_C translated_cross_cov; + # transpose(translated_cross_cov) translated_sigma_XY] + # println("ici 5") + spectrum(x,y) = gaussMultiD(translated_mu_XY,translated_sigma_XY,inv(translated_sigma_XY),[x,y]) + println("ici 6") + z = @. spectrum(xs', ys) + nPartSubset = 20000 + subsetPartID = Int64.(floor.(rand(nPartSubset)*length(particleXs))).+1 + color1=[255 0 0] + color2=[255 230 44] + minSpeed=minimum(particleSpeeds) + maxSpeed=maximum(particleSpeeds) + colorPart=color1.*((particleSpeeds[subsetPartID].-minSpeed)./maxSpeed).+color2.*(1 .-(particleSpeeds[subsetPartID].-minSpeed)./maxSpeed) + transparencyPoints = 1 + trace_tc_2_1 = scatter(x=particleXs[subsetPartID]./1000,y=particleYs[subsetPartID]./1000, + mode="markers", + marker=attr(size=3, + color=particleSpeeds[subsetPartID], + # color="rgba(".*string.(Int64.(floor.(colorPart[:,1]))).*", ".*string.(Int64.(floor.(colorPart[:,2]))).*", ".*string.(Int64.(floor.(colorPart[:,3]))).*", ".*string(transparencyPoints).*")", + showscale=true, + colorscale=[[0,"rgb(255, 230, 44)"],[1,"rgb(255, 0, 0)"]] + ), + zorder=0) + trace_tc_2_2 = contour(x=xs./1000,y=ys./1000,z=z,contours_coloring="lines",line_width=4,showscale=false,colorscale=[[0,"black"],[0.5,"black"],[1,"black"]],zorder=1) + + q1 = plot([trace_tc_2_1,trace_tc_2_2], ed_layout) + + if save_plots + savefig(q1,"test_case_2_particle_contour.html") + end + + line_plot_nPoints = 350 + line_plot_xy = zeros(line_plot_nPoints,2) + line_plot_xy[:,1] = (0:(line_plot_nPoints-1))./(line_plot_nPoints-1)*(xmax-xmin).+xmin + line_plot_xy[:,2] = (y_source) * ones(line_plot_nPoints) + line_plot_length = [sqrt((line_plot_xy[i,1]-line_plot_xy[1,1])^2+(line_plot_xy[i,2]-line_plot_xy[1,2])^2) for i in 1:line_plot_nPoints] + kernel1 = inv(kernel) + println("Start measuring peak_spectrum") + + # Compute model output curve + line_plot_vector = [peak_spectrum(timeOfInterest, ParticleStates, line_plot_xy[i,:],kernel[1:2,1:2],kernel1[1:2,1:2]) for i in 1:line_plot_nPoints] + # line_plot_values = [sqrt(sum(line_plot_vector[i].^2)) for i in 1:line_plot_nPoints] + line_plot_values = [line_plot_vector[i][1] for i in 1:line_plot_nPoints] + println("Finished measuring peak_spectrum") + + # Compute theoretical curve + init_mu_C_measured = [Stc.mean(Matrix(ParticleStates[1,"particleList"][:,["cx"]])), Stc.mean(Matrix(ParticleStates[1,"particleList"][:,["cy"]]))] + # init_mu_C_measured = init_mu_C + init_mu_X_measured = [Stc.mean(Matrix(ParticleStates[3,"particleList"][:,["x"]])), Stc.mean(Matrix(ParticleStates[3,"particleList"][:,["y"]]))] - Δt*2*init_mu_C_measured + init_sigma_X_measured = Stc.cov(Matrix(ParticleStates[3,"particleList"][:,["x","y"]])) + # init_sigma_X_measured = init_sigma[3:4,3:4] + # init_mu_X_measured = init_mu_X + translated_sigma_XY1 = inv(translated_sigma_XY) + translated_mu_XY = init_mu_X_measured+ timesMinutes[timeOfInterest]*60 * [c_x_source, c_y_source] + translated_cross_cov = timesMinutes[timeOfInterest]*60 * init_sigma[1:2,1:2] + line_plot_theory_vector = [translated_mu_C+translated_cross_cov*translated_sigma_XY1*(line_plot_xy[i,:]-translated_mu_XY) for i in 1:line_plot_nPoints] + # line_plot_theory_values = [sqrt(sum(line_plot_theory_vector[i].^2)) for i in 1:line_plot_nPoints] + line_plot_theory_values = [line_plot_theory_vector[i][1] for i in 1:line_plot_nPoints] + + # Compute diffused curve + coef = 0.5 + init_mu_C_measured = [Stc.mean(Matrix(ParticleStates[1,"particleList"][:,["cx"]])), Stc.mean(Matrix(ParticleStates[1,"particleList"][:,["cy"]]))] + # init_mu_C_measured = init_mu_C + init_mu_X_measured = [Stc.mean(Matrix(ParticleStates[3,"particleList"][:,["x"]])), Stc.mean(Matrix(ParticleStates[3,"particleList"][:,["y"]]))] - Δt*2*init_mu_C_measured + init_sigma_X_measured = Stc.cov(Matrix(ParticleStates[3,"particleList"][:,["x","y"]])) + init_sigma_C_measured = Stc.cov(Matrix(ParticleStates[1,"particleList"][:,["cx","cy"]])) + # init_sigma_X_measured = init_sigma[3:4,3:4] + # init_mu_X_measured = init_mu_X + D = coef*sigma_x * coef*sigma_x / Δt * I[1:2,1:2] + translated_diff_sigma_XY = init_sigma_X_measured + (timesMinutes[timeOfInterest]*60)^2 * init_sigma_C_measured + timesMinutes[timeOfInterest]*60 * D + translated_diff_sigma_XY1 = inv(translated_diff_sigma_XY) + translated_cross_cov = timesMinutes[timeOfInterest]*60 * init_sigma_C_measured# + (D) * timesMinutes[timeOfInterest]*60/Δt + translated_mu_XY = init_mu_X_measured + timesMinutes[timeOfInterest]*60 * init_mu_C_measured + line_plot_diff_theory_vector = [translated_mu_C+translated_cross_cov*translated_diff_sigma_XY1*(line_plot_xy[i,:]-translated_mu_XY) for i in 1:line_plot_nPoints] + # line_plot_diff_theory_vector = [translated_mu_C+translated_cross_cov*translated_diff_sigma_XY1*1.09*(line_plot_xy[i,:]-translated_mu_XY) for i in 1:line_plot_nPoints] + #line_plot_diff_theory_values = [sqrt(sum(line_plot_diff_theory_vector[i].^2)) for i in 1:line_plot_nPoints] + line_plot_diff_theory_values = [line_plot_diff_theory_vector[i][1] for i in 1:line_plot_nPoints] + + # Compute linereg through the data and plot it + startPlot = 1 + peakSpeedDataFrame = DataFrame(x=line_plot_length[startPlot:end]./1000, y=line_plot_values[startPlot:end]) + peak_speed_linreg = lm(@formula(y~x), peakSpeedDataFrame) + predict_peak_speed_lm = predict(peak_speed_linreg) + + axis_template = attr(autorange = true, + showgrid = true, zeroline = false, + linecolor = "black", showticklabels = true, + ticks = "" + ) + + LatexFont = attr(color="black",family="Computer Modern",size=28) + LatexFont2 = attr(color="black",family="Computer Modern",size=22) + + psd_layout = Layout(title=attr(text=L"\Large{\text{Peak speed along the axis of propagation}}",font=LatexFont) + ,width=900, height=900 + ,xaxis_title=attr(text=L"\Large{\text{Position along the axis of propagation in } km}",font=LatexFont) + ,yaxis_title=attr(text=L"\Large{\text{Peak speed of particles in } m/s}",font=LatexFont) + ,legend=attr(borderwidth=1,x=0.1, y=0.9,font=LatexFont2) + ,font=LatexFont + ,xaxis=axis_template + ,yaxis=axis_template + ,margin=attr(l=90,r=80,t=80,b=100) + ,template="simple_white" + ) + + + q2 = plot([scatter(x=line_plot_length./1000,y=line_plot_values,name="Model output"), + # scatter(x=line_plot_length./1000,y=line_plot_theory_values, name="Theory without diffusion"), + scatter(x=line_plot_length./1000,y=line_plot_diff_theory_values, name="Theory with diffusion"), + scatter(x=line_plot_length[startPlot:end]./1000,y=predict_peak_speed_lm, name="Linear regression through the data")],psd_layout + ) + + if save_plots + savefig(q2,"test_case_2_peak_speed_distribution.html") + end + +end + +## Computing statistical parameters + +compute_spectrum_bool = false + +if compute_spectrum_bool + counts_1 = Int64.(round.(proba_spectrum_1*10000)) + nSample = sum(counts_1) + sample_1=Array{Any,1}() + + for i in 1:nkX + for j in 1:nkY + for k in 1:counts_1[i,j] + push!(sample_1, [kxs[i],kys[j]]) + end + end + end + + proba_spectrum_end = spectrum_end / sum(spectrum_end) + proba_spectrum_end[max_speed_id[1],max_speed_id[2]] += 1-sum(proba_spectrum_end) + + counts_end = Int64.(round.(proba_spectrum_end*10000)) + nSample = sum(counts_end) + sample_end=Array{Any,1}() + + for i in 1:nkX + for j in 1:nkY + for k in 1:counts_end[i,j] + push!(sample_end, [kxs[i],kys[j]]) + end + end + end + + # proba_spectrum_right = spectrum_right / sum(spectrum_right) + # proba_spectrum_right[max_speed_id[1],max_speed_id[2]] += 1-sum(proba_spectrum_right) + + # counts_right = Int64.(round.(proba_spectrum_right*10000)) + # nSample = sum(counts_right) + # sample_right=Array{Any,1}() + + # for i in 1:nkX + # for j in 1:nkY + # for k in 1:counts_right[i,j] + # push!(sample_right, [kxs[i],kys[j]]) + # end + # end + # end + + # proba_spectrum_left = spectrum_left / sum(spectrum_left) + # proba_spectrum_left[max_speed_id[1],max_speed_id[2]] += 1-sum(proba_spectrum_left) + + # counts_left = Int64.(round.(proba_spectrum_left*10000)) + # nSample = sum(counts_left) + # sample_left=Array{Any,1}() + + # for i in 1:nkX + # for j in 1:nkY + # for k in 1:counts_left[i,j] + # push!(sample_left, [kxs[i],kys[j]]) + # end + # end + # end + + proba_spectrum_forw = spectrum_forw / sum(spectrum_forw) + proba_spectrum_forw[max_speed_id[1],max_speed_id[2]] += 1-sum(proba_spectrum_forw) + + counts_forw = Int64.(round.(proba_spectrum_forw*10000)) + nSample = sum(counts_forw) + sample_forw=Array{Any,1}() + + for i in 1:nkX + for j in 1:nkY + for k in 1:counts_forw[i,j] + push!(sample_forw, [kxs[i],kys[j]]) + end + end + end + + proba_spectrum_back = spectrum_back / sum(spectrum_back) + proba_spectrum_back[max_speed_id[1],max_speed_id[2]] += 1-sum(proba_spectrum_back) + + counts_back = Int64.(round.(proba_spectrum_back*10000)) + nSample = sum(counts_back) + sample_back=Array{Any,1}() + + for i in 1:nkX + for j in 1:nkY + for k in 1:counts_back[i,j] + push!(sample_back, [kxs[i],kys[j]]) + end + end + end + + std_1 = Stc.cov(sample_1) + mean_1 = [Stc.mean([sample_1[i][j] for i in 1:length(sample_1)]) for j in 1:2] + std_end = Stc.cov(sample_end) + mean_end = [Stc.mean([sample_end[i][j] for i in 1:length(sample_end)]) for j in 1:2] + # std_right = Stc.cov(sample_right) + # mean_right = [Stc.mean([sample_right[i][j] for i in 1:length(sample_right)]) for j in 1:2] + # std_left = Stc.cov(sample_left) + # mean_left = [Stc.mean([sample_left[i][j] for i in 1:length(sample_left)]) for j in 1:2] + std_forw = Stc.cov(sample_forw) + mean_forw = [Stc.mean([sample_forw[i][j] for i in 1:length(sample_forw)]) for j in 1:2] + std_back = Stc.cov(sample_back) + mean_back = [Stc.mean([sample_back[i][j] for i in 1:length(sample_back)]) for j in 1:2] + + + + println() + println("------------------------------------------------") + println(" RESULTS :") + println() + + ## T=0 + print("At t=0, the center energy is at (") + print(xyCenter_1[1]) + print(", ") + print(xyCenter_1[2]) + println(")") + print("The mean of the spectrum at this point is (") + print(mean_1[1]) + print(", ") + print(mean_1[2]) + println(")") + println("And the standard deviation is :") + print_mat(std_1) + println() + println() + + ## T=end -> Center + print("At t=60, the center energy is at (") + print(xyCenter_end[1]) + print(", ") + print(xyCenter_end[2]) + println(")") + print("The mean of the spectrum at this point is (") + print(mean_end[1]) + print(", ") + print(mean_end[2]) + println(")") + println("And the standard deviation is :") + print_mat(std_end) + println() + println() + + ## T=end -> Right + # print("At t=60, the right point is at (") + # print(xy_right[1]) + # print(", ") + # print(xy_right[2]) + # println(")") + # print("The mean of the spectrum at this point is (") + # print(mean_right[1]) + # print(", ") + # print(mean_right[2]) + # println(")") + # println("And the standard deviation is :") + # print_mat(std_right) + # println() + # println() + + # ## T=end -> Left + # print("At t=60, the center energy is at (") + # print(xy_left[1]) + # print(", ") + # print(xy_left[2]) + # println(")") + # print("The mean of the spectrum at this point is (") + # print(mean_left[1]) + # print(", ") + # print(mean_left[2]) + # println(")") + # println("And the standard deviation is :") + # print_mat(std_left) + # println() + # println() + + ## T=end -> Forward + print("At t=60, the center energy is at (") + print(xy_forw[1]) + print(", ") + print(xy_forw[2]) + println(")") + print("The mean of the spectrum at this point is (") + print(mean_forw[1]) + print(", ") + print(mean_forw[2]) + println(")") + println("And the standard deviation is :") + print_mat(std_forw) + println() + println() + + ## T=end -> Backward + print("At t=60, the center energy is at (") + print(xy_back[1]) + print(", ") + print(xy_back[2]) + println(")") + print("The mean of the spectrum at this point is (") + print(mean_back[1]) + print(", ") + print(mean_back[2]) + println(")") + println("And the standard deviation is :") + print_mat(std_back) + println() + println() +end + +plot_test_case_3 = true + +if plot_test_case_3 + sigmasComputeType = "multiplePoints" # "singlePoint" or "multiplePoints" + recompute_sigmas_bool = true + timesSeconds = 60*timesMinutes + + if recompute_sigmas_bool + nSamplePoints = 30 + + sigmas_cx = zeros(nTimes) + sigmas_cy = zeros(nTimes) + sigmas_cxy = zeros(nTimes) + sigmas_cx_1 = zeros(nTimes) + sigmas_cy_1 = zeros(nTimes) + sigmas_cxy_1 = zeros(nTimes) + sigmas_C = [zeros(2,2) for _ in 1:nTimes] + sigmas_C_1 = [zeros(2,2) for _ in 1:nTimes] + + for i in 1:nTimes + timeOfInterest = i + translated_mu_C = [c_x_source, c_y_source] + translated_mu_XY = [x_source, y_source] + timesMinutes[timeOfInterest]*60 * [c_x_source, c_y_source] + translated_sigma_XY = init_sigma[3:4,3:4] + (timesMinutes[timeOfInterest]*60)^2 * init_sigma[1:2,1:2] + translated_sigma_C = init_sigma[1:2,1:2] + if sigmasComputeType=="multiplePoints" # Version 2 + xy_center = translated_mu_XY + xy_sigma = translated_sigma_XY + # xy_center = timesSeconds[i].*init_mu_C+init_mu_X + # xy_sigma = timesSeconds[i]^2 .* init_sigma[1:2,1:2] + init_sigma[3:4,3:4] + d = MvNormal(xy_center, xy_sigma) + sampleXYs = rand(d,nSamplePoints) + sampleValues = [] + sampleWeights = [] + # print("computing for sample point number ") + for j in 1:nSamplePoints + # print(", "*string(j)) + res, weight = compute_spectrum_parameters(i, ParticleStates, sampleXYs[:,j], kernel, "gauss") + if res != [0 0; 0 0] + append!(sampleValues, [res]) + append!(sampleWeights, [weight]) + else + print("FOUND ZERO; ") + end + end + sigmas_C[i] = sum(sampleWeights.*sampleValues)/sum(sampleWeights) + elseif sigmasComputeType=="singlePoint" # Version 1 + xy_center = translated_mu_XY + xy_sigma = translated_sigma_XY + xy_chosen = xy_center + sqrt.([translated_sigma_XY[1,1], translated_sigma_XY[2,2]]) + sigmas_C[i] = compute_spectrum_parameters(i, ParticleStates, xy_chosen, kernel, "gauss")[1] + end + + sigmas_C_1[i] = inv(sigmas_C[i]) + + sigmas_cx[i] = sigmas_C[i][1,1] + sigmas_cy[i] = sigmas_C[i][2,2] + sigmas_cxy[i] = sigmas_C[i][2,1] + + sigmas_cx_1[i] = sigmas_C_1[i][1,1] + sigmas_cy_1[i] = sigmas_C_1[i][2,2] + sigmas_cxy_1[i] = sigmas_C_1[i][2,1] + if i%10==0 || i==nTimes + println("Computing sigma for t = "*string(timesMinutes[i])) + end + end + end + + time_long_index = 32 + + data_sigma_cx = DataFrame(x=timesSeconds[time_long_index:end], y=sigmas_cx[time_long_index:end].^-1) + ab_sigma_cx = lm(@formula(y~x), data_sigma_cx) + data_sigma_cy = DataFrame(x=timesSeconds[time_long_index:end], y=sigmas_cy[time_long_index:end].^-1) + ab_sigma_cy = lm(@formula(y~x), data_sigma_cy) + + pearson_sigma_cx = pearson(sigmas_cx[time_long_index:end].^-1, predict(ab_sigma_cx)) + pearson_sigma_cy = pearson(sigmas_cy[time_long_index:end].^-1, predict(ab_sigma_cy)) + + trace1 = scatter(x=timesSeconds,y=sigmas_cx.^-1,name="sigma c_x") + trace2 = scatter(x=timesSeconds,y=sigmas_cy.^-1,name="sigma c_y") + trace3 = scatter(x=timesSeconds[time_long_index:end],y=predict(ab_sigma_cx),name="linreg through sigma c_x; R2="*string(round(pearson_sigma_cx,digits=3))) + trace4 = scatter(x=timesSeconds[time_long_index:end],y=predict(ab_sigma_cy),name="linreg through sigma c_y; R2="*string(round(pearson_sigma_cy,digits=3))) + + trace5 = scatter(x=timesSeconds,y=sigmas_cx.^1,name=L"\text{Model output }(\sigma_{c_x})^2", mode="markers", marker=attr(color="blue")) + trace6 = scatter(x=timesSeconds,y=sigmas_cy.^1,name=L"\text{Model output }(\sigma_{c_y})^2", mode="markers", marker=attr(color="orange")) + + init_sigma_1 = inv(init_sigma) + + init_sigma_C_1 = init_sigma_1[1:2,1:2] + # init_sigma_C_1 = 1 ./(init_sigma[1:2,1:2]) + init_sigma_X_1 = init_sigma_1[3:4,3:4] + # init_sigma_X_1 = 1 ./(init_sigma[3:4,3:4]) + + sigmas_C_t = [inv(t^2*init_sigma_X_1^1 .+ init_sigma_C_1) for t in timesSeconds] + sigmas_cx_t = [sigmas_C_t[t][1,1] for t in 1:length(timesSeconds)] + sigmas_cy_t = [sigmas_C_t[t][2,2] for t in 1:length(timesSeconds)] + + trace7 = scatter(x=timesSeconds,y=sigmas_cx_t, name=L"\text{Theoretical } (\sigma_{c_x})^2", mode="lines", line=attr(dash="dash", color="blue")) + trace8 = scatter(x=timesSeconds,y=sigmas_cy_t, name=L"\text{Theoretical } (\sigma_{c_y})^2", mode="lines", line=attr(dash="dash", color="orange")) + + log_sigma_cx = DataFrame(x=log.(timesSeconds[time_long_index:end]), y=log.(sigmas_cx[time_long_index:end])) + ab_log_sigma_cx = lm(@formula(y~x), log_sigma_cx) + r2_log_sigma_cx = pearson(log_sigma_cx.y,predict(ab_log_sigma_cx)) + log_sigma_cy = DataFrame(x=log.(timesSeconds[time_long_index:end]), y=log.(sigmas_cy[time_long_index:end])) + ab_log_sigma_cy = lm(@formula(y~x), log_sigma_cy) + r2_log_sigma_cy = pearson(log_sigma_cy.y,predict(ab_log_sigma_cy)) + + trace9 = scatter(x=timesSeconds[time_long_index:end], y=exp.(predict(ab_log_sigma_cx))) + trace10 = scatter(x=timesSeconds[time_long_index:end], y=exp.(predict(ab_log_sigma_cy))) + + trace11 = scatter(x=timesSeconds[time_long_index:end], y=20000000 .* timesSeconds[time_long_index:end].^-2) + + # TESTING OTHER CURVES + + # Version 1 + # alpha_mu_Cx = init_mu_C[1]/(sigma_x/Δt) - floor(init_mu_C[1]/(sigma_x/Δt)) + # beta_sigma_Cx = sqrt(init_sigma[1,1])/(sigma_x/Δt) - floor(sqrt(init_sigma[1,1])/(sigma_x/Δt)) + # alpha_mu_Cy = init_mu_C[2]/(sigma_y/Δt) - floor(init_mu_C[2]/(sigma_y/Δt)) + # beta_sigma_Cy = sqrt(init_sigma[2,2])/(sigma_y/Δt) - floor(sqrt(init_sigma[2,2])/(sigma_y/Δt)) + + # coefx = (alpha_mu_Cx-(alpha_mu_Cx^2+beta_sigma_Cx^2)) + # coefy = (alpha_mu_Cy*(1-alpha_mu_Cy/2)+beta_sigma_Cy*(sqrt(2/pi)-beta_sigma_Cy/2)) + # D = sigma_x*sigma_x / Δt * [coefx 0; 0 coefy] + + # Version 2 + # init_mu_cx_corrected = (init_mu_C[1]*Δt/sigma_x - floor.(init_mu_C[1]*Δt/sigma_x))/Δt*sigma_x + # init_mu_cy_corrected = (init_mu_C[2]*Δt/sigma_y - floor.(init_mu_C[2]*Δt/sigma_y))/Δt*sigma_y + # init_sigma_cx_corrected = sqrt(init_sigma[1,1]) + # init_sigma_cy_corrected = sqrt(init_sigma[2,2]) + # # init_sigma_cx_corrected = ((sqrt(init_sigma[1,1])*Δt/sigma_x - floor.(sqrt(init_sigma[1,1])*Δt/sigma_x))/Δt*sigma_x)^2 + # # init_sigma_cy_corrected = ((sqrt(init_sigma[2,2])*Δt/sigma_y - floor.(sqrt(init_sigma[2,2])*Δt/sigma_y))/Δt*sigma_y)^2 + # localx = -init_mu_cx_corrected/(init_sigma_cx_corrected) + # localy = -init_mu_cy_corrected/(init_sigma_cy_corrected) + # phi_x = 1/sqrt(2*pi)*exp(-0.5*(localx)^2) + # phi_y = 1/sqrt(2*pi)*exp(-0.5*(localy)^2) + # Phi_x = 0.5*(1+erf(localx/sqrt(2))) + # Phi_y = 0.5*(1+erf(localy/sqrt(2))) + + # mu_c_upper_x = init_mu_cx_corrected + ((init_sigma_cx_corrected) * phi_x)/(1-Phi_x) + # mu_c_lower_x = init_mu_cx_corrected - ((init_sigma_cx_corrected) * phi_x)/(Phi_x) + # sigma_c_upper_x = init_sigma_cx_corrected * sqrt(1 + (localx* phi_x)/(1 - Phi_x) - (phi_x/(1 - Phi_x))^2) + # sigma_c_lower_x = init_sigma_cx_corrected * sqrt(1 - (localx* phi_x)/(Phi_x) - (phi_x/(Phi_x))^2) + + # mu_c_upper_y = init_mu_cy_corrected + (sqrt(init_sigma_cy_corrected) * phi_y)/(1-Phi_y) + # mu_c_lower_y = init_mu_cy_corrected - (sqrt(init_sigma_cy_corrected) * phi_y)/(Phi_y) + # sigma_c_upper_y = sqrt(init_sigma_cy_corrected * (1 - (localy* phi_y)/(1 - Phi_y) - (phi_y/(1-Phi_y))^2)) + # sigma_c_lower_y = sqrt(init_sigma_cy_corrected * (1 + (localy* phi_y)/(Phi_y) - (phi_y/(Phi_y))^2)) + + # coefx = (1-Phi_x)*(sigma_x*mu_c_upper_x-Δt*(sigma_c_upper_x^2+mu_c_upper_x^2))+Phi_x*(-sigma_x*mu_c_lower_x-Δt*(sigma_c_lower_x^2+mu_c_lower_x^2)) + # coefy = (1-Phi_y)*(sigma_y*mu_c_upper_y-Δt*(sigma_c_upper_y^2+mu_c_upper_y^2))+Phi_y*(-sigma_y*mu_c_lower_y-Δt*(sigma_c_lower_y^2+mu_c_lower_y^2)) + # D = [coefx 0; 0 coefy] + + # Version 3 + # Phi = (x,mu,sigma) -> 0.5*(1+erf((x-mu)/(sigma*sqrt(2)))) + # phi = (x,mu,sigma) -> 1/(sqrt(2*pi))*exp(-0.5*(x-mu)^2/(sigma^2)) + # p=0.0025 + + + # cmin_x = init_mu_C[1] + sqrt(init_sigma[1,1]*2)*erfinv(2*p-1) + # cmax_x = init_mu_C[1] + sqrt(init_sigma[1,1]*2)*erfinv(2*(1-p)-1) + # k_x = Int64(floor(cmin_x*Δt/sigma_x)) + # l_x = Int64(floor(cmax_x*Δt/sigma_x)) + # pos_cx = [(i)*sigma_x/Δt for i in k_x:(l_x+1)] + + # indexes_x = (k_x:l_x) + # probs_x = [(Phi(pos_cx[i+1], init_mu_C[1], sqrt(init_sigma[1,1]))-Phi(pos_cx[i], init_mu_C[1], sqrt(init_sigma[1,1]))) for i in 1:(l_x-k_x+1)] + # means_x = [tn.tnmean(pos_cx[i],pos_cx[i+1],init_mu_C[1],sqrt(init_sigma[1,1])) for i in 1:(l_x-k_x+1)] + # vars_x = [tn.tnvar(pos_cx[i],pos_cx[i+1],init_mu_C[1],sqrt(init_sigma[1,1])) for i in 1:(l_x-k_x+1)] + # coefs_x = probs_x.*( + # sigma_x .* (means_x - indexes_x.*(sigma_x/Δt)) + # - Δt .* ( + # vars_x .^ 2 + means_x .^ 2 + # - 2 .* (indexes_x) .* (Δt / sigma_x) .* means_x + # + ((indexes_x) * sigma_x / Δt) .^ 2 + # ) + # ) + # coefx = sum(coefs_x) + + + # cmin_y = init_mu_C[2] + sqrt(init_sigma[2,2]*2)*erfinv(2*p-1) + # cmax_y = init_mu_C[2] + sqrt(init_sigma[2,2]*2)*erfinv(2*(1-p)-1) + # k_y = Int64(floor(cmin_y*Δt/sigma_y)) + # l_y = Int64(floor(cmax_y*Δt/sigma_y)) + # pos_cy = [(i)*sigma_y/Δt for i in k_y:(l_y+1)] + + # probs_y = [(Phi(pos_cy[i+1], init_mu_C[2], sqrt(init_sigma[2,2]))-Phi(pos_cy[i], init_mu_C[2], sqrt(init_sigma[2,2]))) for i in 1:(l_y-k_y+1)] + # means_y = [tn.tnmean(pos_cy[i],pos_cy[i+1],init_mu_C[2],sqrt(init_sigma[2,2])) for i in 1:(l_y-k_y+1)] + # # means_y = (means_y.*Δt./sigma_y - floor.(means_y.*Δt./sigma_y))./Δt.*sigma_y + # vars_y = [tn.tnvar(pos_cy[i],pos_cy[i+1],init_mu_C[2],sqrt(init_sigma[2,2])) for i in 1:(l_y-k_y+1)] + # coefs_y = 1 + # coefy = sum(coefs_y) + + # # coefx = 884.5 + # # coefy = 599.96 + # D = [coefx 0; 0 coefy] + + # Version 4 + p=1e-5 + nIntPoints = 100000 + f = (c) -> c - floor(c) + g = (c) -> c^2 - 2 * c * floor(c) + floor(c)^2 + compute_Dc = (c,DeltaX,DeltaT) -> DeltaX * f(c/DeltaX*DeltaT) * (DeltaX/DeltaT) - DeltaT * g(c*DeltaT/DeltaX) * (DeltaX/DeltaT)^2 + + cmin_x = init_mu_C[1] + sqrt(init_sigma[1,1]*2)*erfinv(2*p-1) + cmax_x = init_mu_C[1] + sqrt(init_sigma[1,1]*2)*erfinv(2*(1-p)-1) + pos_cx = (((0:nIntPoints)./nIntPoints).*(cmax_x-cmin_x)).+cmin_x + DeltaCx = pos_cx[2]-pos_cx[1] + probas_cx = gaussD.(init_mu_C[1],init_sigma[1,1],pos_cx) + D_cx_values = compute_Dc.(pos_cx, sigma_x, Δt) + D_cx_integrand = probas_cx .* D_cx_values + coefx = sum((D_cx_integrand[1:(end-1)]+D_cx_integrand[2:(end)])/2)*DeltaCx + + cmin_y = init_mu_C[2] + sqrt(init_sigma[2,2]*2)*erfinv(2*p-1) + cmax_y = init_mu_C[2] + sqrt(init_sigma[2,2]*2)*erfinv(2*(1-p)-1) + pos_cy = (((0:nIntPoints)./nIntPoints).*(cmax_y-cmin_y)).+cmin_y + DeltaCy = pos_cy[2]-pos_cy[1] + probas_cy = gaussD.(init_mu_C[2],init_sigma[2,2],pos_cy) + D_cy_values = compute_Dc.(pos_cy, sigma_y, Δt) + D_cy_integrand = probas_cy .* D_cy_values + coefy = sum((D_cy_integrand[1:(end-1)]+D_cy_integrand[2:(end)])/2)*DeltaCy + + D = [coefx 0 ; 0 coefy] + + + timesSeconds2 = (0:(nTimes-1))./(nTimes-1).*(timesSeconds[end]) + + sigmas_C_t_new = [inv(t^2 .* inv(t .* D+ init_sigma[3:4,3:4]) .+ init_sigma_C_1) for t in timesSeconds2] + sigmas_cx_t_new = [sigmas_C_t_new[t][1,1] for t in 1:length(timesSeconds2)] + sigmas_cy_t_new = [sigmas_C_t_new[t][2,2] for t in 1:length(timesSeconds2)] + + derivSigmas_D_C_t_th = [(log.(sigmas_C_t_new[t]).-log.(sigmas_C_t_new[t-1]))./(log(timesSeconds2[t]).-log(timesSeconds2[t-1])) for t in 2:length(timesSeconds2)] + derivSigmas_D_cx_t_th = [derivSigmas_D_C_t_th[t][1,1] for t in 1:(length(timesSeconds2)-1)] + derivSigmas_D_cy_t_th = [derivSigmas_D_C_t_th[t][2,2] for t in 1:(length(timesSeconds2)-1)] + + newTimes, derivSigmas_D_cx_t = compute_derivative(log.(sigmas_cx),log.(timesSeconds), 1) + newTimes, derivSigmas_D_cy_t = compute_derivative(log.(sigmas_cy),log.(timesSeconds), 1) + newTimes = exp.(newTimes) + + trace12 = scatter(x=timesSeconds2, y=sigmas_cx_t_new, name=L"\text{Diffused } (\sigma_{c_x})^2", marker=attr(color="rgb(0, 98, 255)")) + trace13 = scatter(x=timesSeconds2, y=sigmas_cy_t_new, name=L"\text{Diffused } (\sigma_{c_y})^2", marker=attr(color="rgb(226, 45, 0)")) + + trace14 = scatter(x=timesSeconds2[2:end], y=derivSigmas_D_cx_t_th) + trace15 = scatter(x=timesSeconds2[2:end], y=derivSigmas_D_cy_t_th) + + trace16 = scatter(x=newTimes, y=derivSigmas_D_cx_t) + trace17 = scatter(x=newTimes, y=derivSigmas_D_cy_t) + + α = 1000 + β = 30000000 + γ = 17500000 + perfect_1_r = [α/t for t in timesSeconds2[10:end]] + perfect_1_r_2 = [β/t^2 for t in timesSeconds2[10:end]] + perfect_1_r_2_2 = [γ/t^2 for t in timesSeconds2[30:end]] + + trace_perfect_1_r = scatter(x=timesSeconds2[10:end],y=perfect_1_r, + name="\$\\frac{1}{t} \\text{ curve for reference}\$" + , mode="lines", line=attr(dash="dot", color="rgb(112, 187, 112)",width=4) + ) + trace_perfect_1_r_2 = scatter(x=timesSeconds2[10:end],y=perfect_1_r_2, + name="\$\\frac{1}{t^2} \\text{ curve for reference}\$" + , mode="lines", line=attr(dash="dot", color="rgb(181, 105, 178)",width=4) + ) + trace_perfect_1_r_2_2 = scatter(x=timesSeconds2[30:end],y=perfect_1_r_2_2, + name="\$\\frac{1}{t^2} \\text{ curve for reference}\$" + , mode="lines", line=attr(dash="dot", color="rgb(181, 105, 178)",width=4) + ) + + + # END TESTING OTHER CURVES + + axis_template = attr(autorange = true, + showgrid = true, zeroline = false, + linecolor = "black", showticklabels = true, + ticks = "" + ) + + axis_template_x_2 = attr(showgrid = true, zeroline = false, + linecolor = "black", showticklabels = true, + ticks = "", range = log10.([2500, 7500]) + ) + + axis_template_y_2 = attr(showgrid = true, zeroline = false, + linecolor = "black", showticklabels = true, + ticks = "", range = log10.([0.12, 1.34]) + ) + + LatexFont = attr(color="black",family="Computer Modern",size=28) + LatexFontlegend = attr(color="black",family="Computer Modern",size=40) + + sn_layout = Layout(yaxis_type="log",xaxis_type="log", + title=attr(text=L"\LARGE{\text{Evolution of the local } C_x \text{ energy spectrum variance in time}}",font=LatexFont) + ,width=1600, height=1000 + ,xaxis_title=L"\LARGE{\text{time } (sec)}" + ,yaxis_title=L"\LARGE{(\sigma_{c})^2}" + #,legend=attr(borderwidth=1,x=0.5, y=0.5,font=LatexFont) + ,legend=attr(borderwidth=1,x=0.05, y=0.05,font=LatexFontlegend) + ,font=LatexFont + ,xaxis=axis_template + ,yaxis=axis_template + ,margin=attr(l=90,r=80,t=80,b=140) + ,template="simple_white" + ) + + sn_layout2 = Layout(yaxis_type="log",xaxis_type="log", + title=attr(text=L"\LARGE{\text{Evolution of the local } C_y \text{ energy spectrum variance in time}}",font=LatexFont) + ,width=1600, height=1000 + ,xaxis_title=L"\LARGE{\text{time } (sec)}" + ,yaxis_title=L"\LARGE{(\sigma_{c})^2}" + #,legend=attr(borderwidth=1,x=0.5, y=0.5,font=LatexFont) + ,legend=attr(borderwidth=1,x=0.05, y=0.05,font=LatexFontlegend) + ,font=LatexFont + ,xaxis=axis_template + ,yaxis=axis_template + ,margin=attr(l=90,r=80,t=80,b=140) + ,template="simple_white" + ) + + tc3_1 = plot([trace5, trace7, trace12, trace_perfect_1_r, trace_perfect_1_r_2 + ],sn_layout + ) + + tc3_2 = plot([trace6, trace8, trace13, trace_perfect_1_r, trace_perfect_1_r_2_2 + ],sn_layout2 + ) + + save_plots = true + if save_plots + savefig(tc3_1,"test_case_2_spectral_peak_narrowing_cx.html") + savefig(tc3_2,"test_case_2_spectral_peak_narrowing_cy.html") + # savefig(tc3_3,"test_case_2_t3.html") + end + + tc3_3 = plot([trace14, trace16, trace17] + ,Layout(xaxis_type="log" + ,title="LogSlope of the spectrum variance in time" + ) + ) + + tc3_4 = plot([trace1, trace2, trace3, trace4],Layout(#yaxis_type="log",xaxis_type="log", + title="Evolution of the local energy spectrum variance in time" + ,width=1000, height=1000 + ,xaxis_title="\\text{time} (sec)" + ,yaxis_title="sigma_c" + ,legend=attr(borderwidth=3,x=0.1, y=0.8,font=attr(size=18)) + ,font=attr(size=20) + ,template="simple_white" + ) + ) + + # Plotting the space distribution + + plotting_times = [2, Int64(floor(size(MeshState)[1]/2))+2, size(MeshState)[1]] + + plotLog = false + colorbarDelay = 20 + width = 930 + height = 300 + showTitle = false + if plotLog + cRange = [-10, maximum(Matrix(log.(MeshState[plotting_times[1]+colorbarDelay, "mesh_state"])))] + + tc3_t1 = plot_state_and_error_points(log.(MeshState[plotting_times[1], "mesh_state"]), xs./1000, ys./1000, cRange, width, height; showTitle) + tc3_t2 = plot_state_and_error_points(log.(MeshState[plotting_times[2], "mesh_state"]), xs./1000, ys./1000, cRange, width, height; showTitle) + tc3_t3 = plot_state_and_error_points(log.(MeshState[plotting_times[3], "mesh_state"]), xs./1000, ys./1000, cRange, width, height; showTitle) + else + cRange = [0, maximum(Matrix(MeshState[plotting_times[2]+colorbarDelay, "mesh_state"]))] + + tc3_t1 = plot_state_and_error_points(MeshState[plotting_times[1], "mesh_state"], xs./1000, ys./1000, cRange, width, height; showTitle) + tc3_t2 = plot_state_and_error_points(MeshState[plotting_times[2], "mesh_state"], xs./1000, ys./1000, cRange, width, height; showTitle) + tc3_t3 = plot_state_and_error_points(MeshState[plotting_times[3], "mesh_state"], xs./1000, ys./1000, cRange, width, height; showTitle) + end + + save_plots = true + if save_plots + savefig(tc3_t1,"test_case_3_t1.html") + savefig(tc3_t2,"test_case_3_t2.html") + savefig(tc3_t3,"test_case_3_t3.html") + println("Plotting times for the test case 3 energy distribution : "*string(MeshState[plotting_times[1], "times"])*", "*string(MeshState[plotting_times[2], "times"])*", "*string(MeshState[plotting_times[3], "times"])) + end + +end \ No newline at end of file From a77840cc0be888f1493e848fa200045876cd3fb3 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Thu, 24 Jul 2025 10:19:35 +0200 Subject: [PATCH 14/37] added config files for the test case 2 of the paper --- tests/T04_2D_box_2d_2.jl | 26 ++++---- tests/batch_join.jl | 88 +++++++++++++++++++++++++ tests/test_case_2.jl | 120 +++------------------------------- tests/test_case_2_batch1.jl | 123 +++++++++++++++++++++++++++++++++++ tests/test_case_2_batch10.jl | 123 +++++++++++++++++++++++++++++++++++ tests/test_case_2_batch2.jl | 123 +++++++++++++++++++++++++++++++++++ tests/test_case_2_batch3.jl | 123 +++++++++++++++++++++++++++++++++++ tests/test_case_2_batch4.jl | 123 +++++++++++++++++++++++++++++++++++ tests/test_case_2_batch5.jl | 123 +++++++++++++++++++++++++++++++++++ tests/test_case_2_batch6.jl | 123 +++++++++++++++++++++++++++++++++++ tests/test_case_2_batch7.jl | 123 +++++++++++++++++++++++++++++++++++ tests/test_case_2_batch8.jl | 123 +++++++++++++++++++++++++++++++++++ tests/test_case_2_batch9.jl | 123 +++++++++++++++++++++++++++++++++++ tests/test_case_2_single.jl | 123 +++++++++++++++++++++++++++++++++++ 14 files changed, 1462 insertions(+), 125 deletions(-) create mode 100644 tests/batch_join.jl create mode 100644 tests/test_case_2_batch1.jl create mode 100644 tests/test_case_2_batch10.jl create mode 100644 tests/test_case_2_batch2.jl create mode 100644 tests/test_case_2_batch3.jl create mode 100644 tests/test_case_2_batch4.jl create mode 100644 tests/test_case_2_batch5.jl create mode 100644 tests/test_case_2_batch6.jl create mode 100644 tests/test_case_2_batch7.jl create mode 100644 tests/test_case_2_batch8.jl create mode 100644 tests/test_case_2_batch9.jl create mode 100644 tests/test_case_2_single.jl diff --git a/tests/T04_2D_box_2d_2.jl b/tests/T04_2D_box_2d_2.jl index 211b48d..cfc1735 100644 --- a/tests/T04_2D_box_2d_2.jl +++ b/tests/T04_2D_box_2d_2.jl @@ -35,13 +35,13 @@ using Revise #using ProfileView # %% -save_path = "plots/tests/T04_box_2d_2/" +save_path = "plots/tests/paper/T04_box_2d_2/" mkpath(save_path) # % Parameters U10,V10 = 10.0, 10.0 dt_ODE_save = 30minutes -DT = 30minutes +DT = 10minutes # version 3 r_g0 = 0.85 @@ -89,7 +89,7 @@ typeof(winds.u(1e3, 1e3, 11)) # typeof(winds.u(x, y, t)) # %% -grid = TwoDGrid(10e3, 31, 10e3, 31) +grid = TwoDGrid(10e3, 101, 10e3, 101) mesh = TwoDGridMesh(grid, skip=1); gn = TwoDGridNotes(grid); @@ -108,7 +108,7 @@ particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, # define V4 parameters absed on Const NamedTuple: default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -plt.scalefontsizes(1.75) +#plt.scalefontsizes(1.75) # define setting and standard initial conditions WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); @@ -135,7 +135,7 @@ ODE_settings = PW.ODESettings( save_everystep=false) -default_particle = ParticleDefaults(1, 0, 2.12, 5000.0, 500.0, π/4) +default_particle = ParticleDefaults(1, 1.5, 1.5, 500.0, 500.0, π/4) # Define grid #grid = TwoDGrid(150e3, 50, 150e3, 50) @@ -160,25 +160,25 @@ wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, ODEsets=ODE_settings, # ODE_settings #ODEinit_type="wind_sea", # default_ODE_parameters #ODEinit_type="mininmal", - #ODEinit_type=default_particle, + ODEinit_type=default_particle, periodic_boundary=false, boundary_type="same", #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), movie=true, plot_steps=true, - plot_savepath="plots/tests/T04_box_2d_2/nonparametric", + plot_savepath="plots/tests/paper/T04_box_2d_2/nonparametric", angular_spreading_type="nonparametric" - ,n_particles_launch=20 + ,n_particles_launch=10000 ) -PS1 = PointSource(default_particle,0.0) -SourcesList = Array{Any,1}() -push!(SourcesList, PS1) +#PS1 = PointSource(default_particle,0.0) +#SourcesList = Array{Any,1}() +#push!(SourcesList, PS1) ### build Simulation #wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=4hours)#1hours) -wave_simulation = Simulation(wave_model, Δt=2minutes, stop_time=60minutes)#1hours) -initialize_wave_sources!(wave_simulation, SourcesList) +wave_simulation = Simulation(wave_model, Δt=1.4minutes, stop_time=60minutes)#1hours) +#initialize_wave_sources!(wave_simulation, SourcesList) initialize_simulation!(wave_simulation) diff --git a/tests/batch_join.jl b/tests/batch_join.jl new file mode 100644 index 0000000..b3ff15c --- /dev/null +++ b/tests/batch_join.jl @@ -0,0 +1,88 @@ +using DataFrames, DelimitedFiles, CSV + +# Defining helper functions + +function unit_dec(a) + unit=string(Int64(floor((a)))) + dec=string(Int64(floor(10*(a-floor((a)))))) + return unit*","*dec +end + +# Starting the merge + +parentPath = pwd()*"/plots/test_case_2/model_outputs" +mkdir(parentPath) +mkdir(parentPath*"/data") +mkdir(parentPath*"/plots") +# parentPath = "/home1/datahome/tprotin/Travail/PiCLES/PiCLES/plots/tests/paper/test_case_3/v3_half_cell" +println("------------ Reading the data from : "* parentPath * " ------------") + +nBatch = 10 +paths = [parentPath*"_batch"*string(i) for i in 1:nBatch] + +path = paths[1]*"/data/simu_infos.csv" +path2 = paths[1]*"/data/sigma.csv" +data, header = readdlm(path, ',', header=true) +data2, header2 = readdlm(path2, ',', header=true) + +simu_infos = DataFrame(data, vec(header)) +init_sigma_df = DataFrame(data2, vec(header2)) + +init_sigma = Matrix(init_sigma_df) +Nx = simu_infos.Nx[1] +Ny = simu_infos.Ny[1] +xmin = simu_infos.xmin[1] +xmax = simu_infos.xmax[1] +ymin = simu_infos.ymin[1] +ymax = simu_infos.ymax[1] +lne_source = simu_infos.lne_source[1] +c_x_source = simu_infos.c_x_source[1] +c_y_source = simu_infos.c_y_source[1] +x_source = simu_infos.x_source[1] +y_source = simu_infos.y_source[1] +angular_spread_source = simu_infos.angular_spread_source[1] +Δt = simu_infos.Δt[1] +stop_time = simu_infos.stop_time[1] + +nTimes = Int64(ceil(stop_time/Δt))+1 + +times = (0:(nTimes))*Δt +timesMinutes = times/60 + +timesMinutesString = unit_dec.(timesMinutes) + + +ParticleStates = DataFrame([[],[]],["times", "particleList"]) +MeshState = DataFrame([[],[]],["times", "mesh_state"]) + + +for i in 1:nTimes + temp_df1 = DataFrame([[],[],[],[],[],[]], ["id", "logE", "cx", "cy", "x", "y"]) + columnNames = ["Column"*string(Int64(i)) for i in 1:Nx] + temp_df2 = DataFrame(zeros(70,300), columnNames) + for j in 1:nBatch + path1 = paths[j]*"/data/particles_"*timesMinutesString[i]*".csv" + path2 = paths[j]*"/data/mesh_values_"*timesMinutesString[i]*".csv" + data1, header1 = readdlm(path1, ',', header=true) + data2, header2 = readdlm(path2, ',', header=true) + + read_df1 = DataFrame(data1, vec(header1)) + read_df2 = DataFrame(data2, vec(header2)) + + append!(temp_df1, read_df1) + temp_df2 = read_df2 .+ temp_df2 + end + temp_df1 = DataFrame([[timesMinutes[i]], [temp_df1]], ["times", "particleList"]) + temp_df2 = DataFrame([[timesMinutes[i]], [temp_df2]], ["times", "mesh_state"]) + append!(ParticleStates, temp_df1) + append!(MeshState, temp_df2) + + time = ParticleStates[end,"times"]*60 + println(time) + + sec=string(Int64(floor((time)/60))) + dec=string(Int64(floor(10*(time/60-floor((time)/60))))) + + CSV.write(parentPath*"/data/mesh_values_"*sec*","*dec*".csv", temp_df2[end,"mesh_state"]) + CSV.write(parentPath*"/data/particles_"*sec*","*dec*".csv", temp_df1[end,"particleList"]) +end diff --git a/tests/test_case_2.jl b/tests/test_case_2.jl index f3a2ccd..5669817 100644 --- a/tests/test_case_2.jl +++ b/tests/test_case_2.jl @@ -1,117 +1,13 @@ ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg +using Pkg, Dates +println(now()) Pkg.activate(".") -import Plots as plt -using Setfield, IfElse +n_batch = 10 -using PiCLES.ParticleSystems: particle_waves_v6 as PW +for i in 1:n_batch + include("test_case_2_batch"*string(i)*".jl") +end -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -save_path = "plots/tests/paper/test_case_3/" -mkpath(save_path) - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/tests/paper/test_case_3/v2_half_cell_batch1", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=1000000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) +include("batch_join.jl") +println(now()) diff --git a/tests/test_case_2_batch1.jl b/tests/test_case_2_batch1.jl new file mode 100644 index 0000000..4826f0d --- /dev/null +++ b/tests/test_case_2_batch1.jl @@ -0,0 +1,123 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +batch_number = "1" + +save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" +mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=10000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch10.jl b/tests/test_case_2_batch10.jl new file mode 100644 index 0000000..1ef43f8 --- /dev/null +++ b/tests/test_case_2_batch10.jl @@ -0,0 +1,123 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +batch_number = "10" + +save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" +mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=10000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch2.jl b/tests/test_case_2_batch2.jl new file mode 100644 index 0000000..cfb37a2 --- /dev/null +++ b/tests/test_case_2_batch2.jl @@ -0,0 +1,123 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +batch_number = "2" + +save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" +mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=10000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch3.jl b/tests/test_case_2_batch3.jl new file mode 100644 index 0000000..0ad3dae --- /dev/null +++ b/tests/test_case_2_batch3.jl @@ -0,0 +1,123 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +batch_number = "3" + +save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" +mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=10000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch4.jl b/tests/test_case_2_batch4.jl new file mode 100644 index 0000000..58f0db6 --- /dev/null +++ b/tests/test_case_2_batch4.jl @@ -0,0 +1,123 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +batch_number = "4" + +save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" +mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=10000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch5.jl b/tests/test_case_2_batch5.jl new file mode 100644 index 0000000..e14d36e --- /dev/null +++ b/tests/test_case_2_batch5.jl @@ -0,0 +1,123 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +batch_number = "5" + +save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" +mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=10000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch6.jl b/tests/test_case_2_batch6.jl new file mode 100644 index 0000000..764fb6e --- /dev/null +++ b/tests/test_case_2_batch6.jl @@ -0,0 +1,123 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +batch_number = "6" + +save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" +mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=10000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch7.jl b/tests/test_case_2_batch7.jl new file mode 100644 index 0000000..cbd3fe7 --- /dev/null +++ b/tests/test_case_2_batch7.jl @@ -0,0 +1,123 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +batch_number = "7" + +save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" +mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=10000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch8.jl b/tests/test_case_2_batch8.jl new file mode 100644 index 0000000..e4bcbd7 --- /dev/null +++ b/tests/test_case_2_batch8.jl @@ -0,0 +1,123 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +batch_number = "8" + +save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" +mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=10000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch9.jl b/tests/test_case_2_batch9.jl new file mode 100644 index 0000000..bedba23 --- /dev/null +++ b/tests/test_case_2_batch9.jl @@ -0,0 +1,123 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +batch_number = "9" + +save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" +mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=10000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_single.jl b/tests/test_case_2_single.jl new file mode 100644 index 0000000..8c008e9 --- /dev/null +++ b/tests/test_case_2_single.jl @@ -0,0 +1,123 @@ +ENV["JULIA_INCREMENTAL_COMPILE"]=true +using Pkg +Pkg.activate(".") + +import Plots as plt +using Setfield, IfElse + +using PiCLES.ParticleSystems: particle_waves_v6 as PW + +import PiCLES: FetchRelations, ParticleTools +using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource +using PiCLES.Operators: TimeSteppers +using PiCLES.Simulations +using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! + +using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Models.GeometricalOpticsModels + +using Oceananigans.TimeSteppers: Clock, tick! +import Oceananigans: fields +using Oceananigans.Units +import Oceananigans.Utils: prettytime + +using PiCLES.Architectures + +using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed + +using Revise + +batch_number = "11" + +save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" +mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") + +# % Parameters +U10,V10 = 10.0, 10.0 +dt_ODE_save = 30minutes +DT = 2minutes +# version 3 +r_g0 = 0.85 + +# function to define constants +Const_ID = PW.get_I_D_constant() +@set Const_ID.γ = 0.88 +Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) + +u_func(x, y, t) = 0. +v_func(x, y, t) = 0. + +u(x, y, t) = u_func(x, y, t) +v(x, y, t) = v_func(x, y, t) +winds = (u=u, v=v) + +typeof(winds.u) +typeof(winds.u(1e3, 1e3, 11)) + +grid = TwoDGrid(168750, 300, 39375, 70) +mesh = TwoDGridMesh(grid, skip=1); +gn = TwoDGridNotes(grid); + +Revise.retry() + +# define variables based on particle equation + +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); + +# define V4 parameters absed on Const NamedTuple: +default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, + C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); +#plt.scalefontsizes(1.75) + +# define setting and standard initial conditions +WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); +lne_local = log(WindSeamin["E"]) + +ODE_settings = PW.ODESettings( + Parameters=default_ODE_parameters, + # define mininum energy threshold + log_energy_minimum=lne_local, + #maximum energy threshold + log_energy_maximum=log(27), + saving_step=dt_ODE_save, + timestep=DT, + total_time=T=6days, + adaptive=true, + dt=1e-3, #60*10, + dtmin=1e-4, #60*5, + force_dtmin=true, + callbacks=nothing, + save_everystep=false) + + +default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) +Revise.retry() + +wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, + winds=winds, + ODEsys=particle_system, + ODEsets=ODE_settings, # ODE_settings + ODEinit_type=default_particle, + periodic_boundary=false, + boundary_type="same", + movie=true, + plot_steps=true, + save_particles=true, + plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", + angular_spreading_type="nonparametric", + proba_covariance_init = [150 0 0 0; + 0 3 0 0; + 0 0 10^7 0 + 0 0 0 10^7], + n_particles_launch=100000 + ) + +wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) +initialize_simulation!(wave_simulation) + + +@time run!(wave_simulation, cash_store=false, debug=false) From 5b2c5a0b6223648df5279dc2ba816b200c4c00ed Mon Sep 17 00:00:00 2001 From: tomprotin Date: Thu, 24 Jul 2025 10:31:24 +0200 Subject: [PATCH 15/37] added config files for the test case 1 of the paper --- tests/test_case_1.jl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/test_case_1.jl b/tests/test_case_1.jl index 9302e5d..2141b43 100644 --- a/tests/test_case_1.jl +++ b/tests/test_case_1.jl @@ -27,8 +27,12 @@ using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed using Revise -save_path = "plots/tests/paper/test_case_1/" +save_path = "plots/test_case_1/" mkpath(save_path) +mkpath(save_path*"data/") +mkpath(save_path*"plots/") +touch(save_path*"data/simu_info.csv") +touch(save_path*"data/sigma.csv") # % Parameters U10,V10 = 10.0, 10.0 @@ -101,13 +105,13 @@ wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, movie=true, plot_steps=true, save_particles=true, - plot_savepath="plots/tests/paper/test_case_1/v2_pi", + plot_savepath="plots/test_case_1", angular_spreading_type="nonparametric", proba_covariance_init = [1e-50 0 0 0; 0 1e-50 0 0; 0 0 1e-50 0 0 0 0 1e-50], - n_particles_launch=150000 + n_particles_launch=15000 ) wave_simulation = Simulation(wave_model, Δt=0.75minutes, stop_time=60minutes) From a581814b95d08360940792aae395c09558bcd77a Mon Sep 17 00:00:00 2001 From: tomprotin Date: Thu, 24 Jul 2025 10:38:43 +0200 Subject: [PATCH 16/37] corrected the number of particles in test case 1 --- tests/test_case_1.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_case_1.jl b/tests/test_case_1.jl index 2141b43..ba0ae71 100644 --- a/tests/test_case_1.jl +++ b/tests/test_case_1.jl @@ -111,7 +111,7 @@ wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, 0 1e-50 0 0; 0 0 1e-50 0 0 0 0 1e-50], - n_particles_launch=15000 + n_particles_launch=150000 ) wave_simulation = Simulation(wave_model, Δt=0.75minutes, stop_time=60minutes) From 00543fb6cd3fc2639360a3c02b0373ac883fe9f1 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Mon, 15 Sep 2025 13:39:19 +0200 Subject: [PATCH 17/37] removed unnecessary test case files --- tests/test_case_2.jl | 13 ---- tests/test_case_2_batch1.jl | 123 ----------------------------------- tests/test_case_2_batch10.jl | 123 ----------------------------------- tests/test_case_2_batch2.jl | 123 ----------------------------------- tests/test_case_2_batch3.jl | 123 ----------------------------------- tests/test_case_2_batch4.jl | 123 ----------------------------------- tests/test_case_2_batch5.jl | 123 ----------------------------------- tests/test_case_2_batch6.jl | 123 ----------------------------------- tests/test_case_2_batch7.jl | 123 ----------------------------------- tests/test_case_2_batch8.jl | 123 ----------------------------------- tests/test_case_2_batch9.jl | 123 ----------------------------------- tests/test_case_2_single.jl | 123 ----------------------------------- 12 files changed, 1366 deletions(-) delete mode 100644 tests/test_case_2.jl delete mode 100644 tests/test_case_2_batch1.jl delete mode 100644 tests/test_case_2_batch10.jl delete mode 100644 tests/test_case_2_batch2.jl delete mode 100644 tests/test_case_2_batch3.jl delete mode 100644 tests/test_case_2_batch4.jl delete mode 100644 tests/test_case_2_batch5.jl delete mode 100644 tests/test_case_2_batch6.jl delete mode 100644 tests/test_case_2_batch7.jl delete mode 100644 tests/test_case_2_batch8.jl delete mode 100644 tests/test_case_2_batch9.jl delete mode 100644 tests/test_case_2_single.jl diff --git a/tests/test_case_2.jl b/tests/test_case_2.jl deleted file mode 100644 index 5669817..0000000 --- a/tests/test_case_2.jl +++ /dev/null @@ -1,13 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg, Dates -println(now()) -Pkg.activate(".") - -n_batch = 10 - -for i in 1:n_batch - include("test_case_2_batch"*string(i)*".jl") -end - -include("batch_join.jl") -println(now()) diff --git a/tests/test_case_2_batch1.jl b/tests/test_case_2_batch1.jl deleted file mode 100644 index 9b79e8b..0000000 --- a/tests/test_case_2_batch1.jl +++ /dev/null @@ -1,123 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -batch_number = "1" - -save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" -mkpath(save_path) -mkpath(save_path*"data/") -mkpath(save_path*"plots/") -touch(save_path*"data/simu_info.csv") -touch(save_path*"data/sigma.csv") - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=100000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch10.jl b/tests/test_case_2_batch10.jl deleted file mode 100644 index 7bb027a..0000000 --- a/tests/test_case_2_batch10.jl +++ /dev/null @@ -1,123 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -batch_number = "10" - -save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" -mkpath(save_path) -mkpath(save_path*"data/") -mkpath(save_path*"plots/") -touch(save_path*"data/simu_info.csv") -touch(save_path*"data/sigma.csv") - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=100000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch2.jl b/tests/test_case_2_batch2.jl deleted file mode 100644 index cf00a62..0000000 --- a/tests/test_case_2_batch2.jl +++ /dev/null @@ -1,123 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -batch_number = "2" - -save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" -mkpath(save_path) -mkpath(save_path*"data/") -mkpath(save_path*"plots/") -touch(save_path*"data/simu_info.csv") -touch(save_path*"data/sigma.csv") - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=100000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch3.jl b/tests/test_case_2_batch3.jl deleted file mode 100644 index 5ccafe9..0000000 --- a/tests/test_case_2_batch3.jl +++ /dev/null @@ -1,123 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -batch_number = "3" - -save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" -mkpath(save_path) -mkpath(save_path*"data/") -mkpath(save_path*"plots/") -touch(save_path*"data/simu_info.csv") -touch(save_path*"data/sigma.csv") - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=100000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch4.jl b/tests/test_case_2_batch4.jl deleted file mode 100644 index f21015e..0000000 --- a/tests/test_case_2_batch4.jl +++ /dev/null @@ -1,123 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -batch_number = "4" - -save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" -mkpath(save_path) -mkpath(save_path*"data/") -mkpath(save_path*"plots/") -touch(save_path*"data/simu_info.csv") -touch(save_path*"data/sigma.csv") - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=100000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch5.jl b/tests/test_case_2_batch5.jl deleted file mode 100644 index dcd822b..0000000 --- a/tests/test_case_2_batch5.jl +++ /dev/null @@ -1,123 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -batch_number = "5" - -save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" -mkpath(save_path) -mkpath(save_path*"data/") -mkpath(save_path*"plots/") -touch(save_path*"data/simu_info.csv") -touch(save_path*"data/sigma.csv") - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=100000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch6.jl b/tests/test_case_2_batch6.jl deleted file mode 100644 index afb8160..0000000 --- a/tests/test_case_2_batch6.jl +++ /dev/null @@ -1,123 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -batch_number = "6" - -save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" -mkpath(save_path) -mkpath(save_path*"data/") -mkpath(save_path*"plots/") -touch(save_path*"data/simu_info.csv") -touch(save_path*"data/sigma.csv") - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=100000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch7.jl b/tests/test_case_2_batch7.jl deleted file mode 100644 index 317a553..0000000 --- a/tests/test_case_2_batch7.jl +++ /dev/null @@ -1,123 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -batch_number = "7" - -save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" -mkpath(save_path) -mkpath(save_path*"data/") -mkpath(save_path*"plots/") -touch(save_path*"data/simu_info.csv") -touch(save_path*"data/sigma.csv") - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=100000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch8.jl b/tests/test_case_2_batch8.jl deleted file mode 100644 index b60f9f7..0000000 --- a/tests/test_case_2_batch8.jl +++ /dev/null @@ -1,123 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -batch_number = "8" - -save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" -mkpath(save_path) -mkpath(save_path*"data/") -mkpath(save_path*"plots/") -touch(save_path*"data/simu_info.csv") -touch(save_path*"data/sigma.csv") - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=100000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_batch9.jl b/tests/test_case_2_batch9.jl deleted file mode 100644 index 53544e5..0000000 --- a/tests/test_case_2_batch9.jl +++ /dev/null @@ -1,123 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -batch_number = "9" - -save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" -mkpath(save_path) -mkpath(save_path*"data/") -mkpath(save_path*"plots/") -touch(save_path*"data/simu_info.csv") -touch(save_path*"data/sigma.csv") - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=100000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=120minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) diff --git a/tests/test_case_2_single.jl b/tests/test_case_2_single.jl deleted file mode 100644 index 67f31d4..0000000 --- a/tests/test_case_2_single.jl +++ /dev/null @@ -1,123 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed - -using Revise - -batch_number = "11" - -save_path = "plots/test_case_2/model_outputs_batch"*batch_number*"/" -mkpath(save_path) -mkpath(save_path*"data/") -mkpath(save_path*"plots/") -touch(save_path*"data/simu_info.csv") -touch(save_path*"data/sigma.csv") - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 2minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) - -grid = TwoDGrid(168750, 300, 39375, 70) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -Revise.retry() - -# define variables based on particle equation - -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ); -lne_local = log(WindSeamin["E"]) - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local, - #maximum energy threshold - log_energy_maximum=log(27), - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1., 15., 0., 5000, 18750.0, π/4) -Revise.retry() - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - movie=true, - plot_steps=true, - save_particles=true, - plot_savepath="plots/test_case_2/model_outputs_batch"*batch_number*"", - angular_spreading_type="nonparametric", - proba_covariance_init = [150 0 0 0; - 0 3 0 0; - 0 0 10^7 0 - 0 0 0 10^7], - n_particles_launch=100000 - ) - -wave_simulation = Simulation(wave_model, Δt=1minutes, stop_time=60minutes) -initialize_simulation!(wave_simulation) - - -@time run!(wave_simulation, cash_store=false, debug=false) From 5d5163b23c5ddd7f4ac50750e1ce918cb49ab6a9 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Mon, 15 Sep 2025 15:34:36 +0200 Subject: [PATCH 18/37] further modified and removed useless test case files --- tests/T03_PIC_tripolar_realistic.jl | 2 +- tests/T04_2D_box_2d_2.jl | 353 ---------------------------- tests/T04_2D_box_rotation.jl | 3 +- tests/batch_join.jl | 88 ------- tests/test_case_1.jl | 2 +- 5 files changed, 3 insertions(+), 445 deletions(-) delete mode 100644 tests/T04_2D_box_2d_2.jl delete mode 100644 tests/batch_join.jl diff --git a/tests/T03_PIC_tripolar_realistic.jl b/tests/T03_PIC_tripolar_realistic.jl index d1ed6f2..9bf3951 100644 --- a/tests/T03_PIC_tripolar_realistic.jl +++ b/tests/T03_PIC_tripolar_realistic.jl @@ -1,7 +1,7 @@ # %% # ENV["JULIA_INCREMENTAL_COMPILE"] = true using Pkg -Pkg.activate(".") +Pkg.activate("PiCLES/") import Plots as plt using Setfield, IfElse diff --git a/tests/T04_2D_box_2d_2.jl b/tests/T04_2D_box_2d_2.jl deleted file mode 100644 index cfc1735..0000000 --- a/tests/T04_2D_box_2d_2.jl +++ /dev/null @@ -1,353 +0,0 @@ -ENV["JULIA_INCREMENTAL_COMPILE"]=true -using Pkg -Pkg.activate(".") - -#using ModelingToolkit, DifferentialEquations -#using ModelingToolkit#: @register_symbolic -#using Plots -import Plots as plt -using Setfield, IfElse - -using PiCLES.ParticleSystems: particle_waves_v6 as PW - -import PiCLES: FetchRelations, ParticleTools -using PiCLES.Operators.core_2D_spread: ParticleDefaults, InitParticleInstance, GetGroupVelocity, PointSource -using PiCLES.Operators: TimeSteppers -using PiCLES.Simulations -using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! - -using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh -using PiCLES.Models.GeometricalOpticsModels - -using Oceananigans.TimeSteppers: Clock, tick! -import Oceananigans: fields -using Oceananigans.Units -import Oceananigans.Utils: prettytime - -using PiCLES.Architectures -using GLMakie - -using PiCLES.Operators.core_2D_spread: GetGroupVelocity, speed -using PiCLES.Plotting.movie: init_movie_2D_box_plot - -using Revise -# debugging: -#using ProfileView - -# %% -save_path = "plots/tests/paper/T04_box_2d_2/" -mkpath(save_path) - -# % Parameters -U10,V10 = 10.0, 10.0 -dt_ODE_save = 30minutes -DT = 10minutes -# version 3 -r_g0 = 0.85 - -# function to define constants -Const_ID = PW.get_I_D_constant() -@set Const_ID.γ = 0.88 -Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) - - -# u(x, y, t) = 0.01 + U10 * sin(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) -# v(x, y, t) = 0.01 - V10 * cos(t / (6*60*60 * 2π) ) * sin(x / 50e3) * sin(y / 50e3) -u_std= 2e3 *1 -v_std= 2e3 *1 -#u_func(x, y, t) = U10 * exp( - (x - 5e3)^2/ u_std^2) * exp( - (y - 5e3)^2/ v_std^2) * sin(t*2 / (1 * 60 * 60 * 2π)) -#v_func(x, y, t) = V10 * exp( - (x - 5e3)^2/ u_std^2) * exp( - (y - 5e3)^2/ v_std^2) * cos(t*2 / (1 * 60 * 60 * 2π) ) - -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. - -# u_func(x, y, t) = 0.1 + IfElse.ifelse.( sin(t * 6 / (1 * 60 * 60 * 2π)) > 0 , -# sin(t * 6 / (1 * 60 * 60 * 2π)) *U10 * exp(-(x - 5e3)^2 / u_std^2) * exp(-(y - 5e3)^2 / v_std^2), -# 0.1) -# v_func(x, y, t) = 0.1 + IfElse.ifelse.(sin(t * 3 / (1 * 60 * 60 * 2π)) > 0, -# 0.0, -# -0.0) - -# u_func(x, y, t) = IfElse.ifelse.(x .< 5e3, U10, 0.2) + y * 0 + t * 0 -# v_func(x, y, t) = (IfElse.ifelse.(x .< 5e3, V10, 0.2) + y * 0) .* cos(t * 3 / (1 * 60 * 60 * 2π)) - -# this shuold hopefully work -# u(x, y, t) = x * 0 + y * 0 + t * 0/ DT + 5.0 -# v(x, y, t) = x * 0 + y * 0 + t * 0/ DT + 10.0 - -u(x, y, t) = u_func(x, y, t) -v(x, y, t) = v_func(x, y, t) -winds = (u=u, v=v) - -typeof(winds.u) -typeof(winds.u(1e3, 1e3, 11)) -#typeof(u_func(1e3, 1e3, 11)) -#typeof(winds.u(x,y,t)) - -# u2 = winds.u(x, y, t) -# typeof(u2) -# typeof(winds.u(x, y, t)) -# %% - -grid = TwoDGrid(10e3, 101, 10e3, 101) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); - -#heatmap( v.(mesh.x, mesh.y, 0) ) - - -Revise.retry() - -# define variables based on particle equation - -#ProfileView.@profview -#ProfileView.@profview -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); -#particle_equations = PW3.particle_equations_vec5(u, v, u, v, γ=0.88, q=Const_ID.q); - -# define V4 parameters absed on Const NamedTuple: -default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, - C_φ = Const_ID.c_β, C_e = Const_ID.C_e, g= 9.81 ); -#plt.scalefontsizes(1.75) - -# define setting and standard initial conditions -WindSeamin = FetchRelations.get_minimal_windsea(U10, V10, DT ); -#WindSeamin = FetchRelations.get_minimal_windsea(u(0, 0, 0), v(0, 0, 0), DT / 2) -#WindSeamin = FetchRelations.get_initial_windsea(u(0, 0, 0), v(0, 0, 0), DT/5) -lne_local = log(WindSeamin["E"]) -cg_u_local = WindSeamin["cg_bar_x"] -cg_v_local = WindSeamin["cg_bar_y"] - -ODE_settings = PW.ODESettings( - Parameters=default_ODE_parameters, - # define mininum energy threshold - log_energy_minimum=lne_local,#log(FetchRelations.Eⱼ(0.1, DT)), - #maximum energy threshold - log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m - saving_step=dt_ODE_save, - timestep=DT, - total_time=T=6days, - adaptive=true, - dt=1e-3, #60*10, - dtmin=1e-4, #60*5, - force_dtmin=true, - callbacks=nothing, - save_everystep=false) - - -default_particle = ParticleDefaults(1, 1.5, 1.5, 500.0, 500.0, π/4) - -# Define grid -#grid = TwoDGrid(150e3, 50, 150e3, 50) - -# gridmesh = [(i, j) for i in gn.x, j in gn.y]; -# mesh.x = [i for i in gn.x, j in gn.y]; -# mesh.y = [j for i in gn.x, j in gn.y]; -# # mesh.x = mesh.x[1:3:end, 1:3:end]; -# # mesh.y = mesh.y[1:3:end, 1:3:end]; - - -# plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(u.(mesh.x, mesh.y, 0))) - -# plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(v.(mesh.x, mesh.y, 0))) -# %% build model -Revise.retry() - - -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - #ODEinit_type="wind_sea", # default_ODE_parameters - #ODEinit_type="mininmal", - ODEinit_type=default_particle, - periodic_boundary=false, - boundary_type="same", - #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), - movie=true, - plot_steps=true, - plot_savepath="plots/tests/paper/T04_box_2d_2/nonparametric", - angular_spreading_type="nonparametric" - ,n_particles_launch=10000 - ) - -#PS1 = PointSource(default_particle,0.0) -#SourcesList = Array{Any,1}() -#push!(SourcesList, PS1) - -### build Simulation -#wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=4hours)#1hours) -wave_simulation = Simulation(wave_model, Δt=1.4minutes, stop_time=60minutes)#1hours) -#initialize_wave_sources!(wave_simulation, SourcesList) -initialize_simulation!(wave_simulation) - - -#init_state_store!(wave_simulation, save_path) -#wave_simulation.model.MovieState = wave_simulation.model.State - -@time run!(wave_simulation, cash_store=true, debug=false) -#reset_simulation!(wave_simulation) -# run simulation2 -#ProfileView.@profview run!(wave_simulation, cash_store=true, debug=true) - - -istate = wave_simulation.store.store[end]; -p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, istate[:, :, 1]) - - -# %% -# show all Failed particles -using PiCLES.Utils: ParticleTools - -Revise.retry() -DD = ParticleTools.ParticleToDataframe(wave_simulation.model.FailedCollection) - -DD_stats = ParticleTools.ParticleStatsToDataframe(wave_simulation.model.FailedCollection) - -#sum(DD_stats.boundary) - -function plot_state_and_error_points(wave_simulation, FailedTable) - plt.plot() - - p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(wave_simulation.model.State[:, :, 1])) - - for xy in FailedTable.position_xy - x = xy[1] / 1e3 - y = xy[2] / 1e3 - plt.scatter!((x, y), color="red", label="wind") - end - - plt.plot!(legend=:none, title="c_g", ylabel="cg m/s", xlabel="position index x") |> display -end - -plot_state_and_error_points(wave_simulation, DD_stats) -# %% -#plt.savefig(joinpath([save_path, "energy_plot_no_spread.png"])) - -## testing single ODES -PF = wave_simulation.model.FailedCollection[end] -PF.Particle -#PF.Particle.ODEIntegrator.u = [-15.441984291167334, 0.006707651986269529, 0.003889144130029894, 4000.0, 2333.3333333333335] -PF.Particle.ODEIntegrator.u -PF.Particle.ODEIntegrator.t -PF.Particle.ODEIntegrator.sol.t -PF.Particle.ODEIntegrator.sol.u -PF.Particle.ODEIntegrator.sol.prob.u0 - -using PiCLES.Operators.core_2D_spread: Get_u_FromShared, GetVariablesAtVertex -S_state = Get_u_FromShared(PF.Particle, wave_simulation.model.MovieState) -ui = GetVariablesAtVertex(S_state, PF.Particle.position_xy[1], PF.Particle.position_xy[2]) - -usel = PF.Particle.ODEIntegrator.sol.prob.u0 -t_sel = PF.Particle.ODEIntegrator.sol.u -index, weight = PIC.compute_weights_and_index(grid, usel[4], usel[5]) - -using PiCLES: ParticleInCell as PIC -index, weight = PIC.compute_weights_and_index(grid, PF.Particle.ODEIntegrator.u[4], PF.Particle.ODEIntegrator.u[5]) - - -# try manual solution with the same initial conditions -using DifferentialEquations - -#PF.Particle.ODEIntegrator.u = ui -ui2 = copy(PF.Particle.ODEIntegrator.sol.prob.u0) -reinit!(PF.Particle.ODEIntegrator, ui2, erase_sol=false, reset_dt=false, reinit_cache=true) -u_modified!(PF.Particle.ODEIntegrator, true) -#auto_dt_reset!(PF.Particle.ODEIntegrator) -PF.Particle.ODEIntegrator.t -# set_t!(PF.Particle.ODEIntegrator, PF.Particle.ODEIntegrator.sol.t[end]) - -wind_tuple = winds.u(PF.Particle.position_xy[1], PF.Particle.position_xy[2], PF.Particle.ODEIntegrator.t), winds.v(PF.Particle.position_xy[1], PF.Particle.position_xy[2], PF.Particle.ODEIntegrator.t) -step!(PF.Particle.ODEIntegrator, DT, true) -PF.Particle.ODEIntegrator.u - - -function set_u_and_t!(integrator, u_new, t_new) - integrator.u = u_new - integrator.t = t_new -end - -#5min -DT = 5min#wave_simulation.model.ODEsettings.timestep -ui2 -set_u_and_t!(PF.Particle.ODEIntegrator, ui2, 0.0) -auto_dt_reset!(PF.Particle.ODEIntegrator) -step!(PF.Particle.ODEIntegrator, DT, true) -PF.Particle.ODEIntegrator.u - -#index, weight = PIC.compute_weights_and_index(grid, PF.Particle.ODEIntegrator.u[4], PF.Particle.ODEIntegrator.u[5]) - -#PF.Particle.ODEIntegrator.sol -#wave_simulation.model.winds.u() - -# %% -#PF.Particle.boundary -Revise.retry() - -istate = wave_simulation.store.store[end]; -#istate = wave_simulation.store.store[5]; -#wave_simulation.model.ParticleCollection[105] - -cg= GetGroupVelocity(istate) -p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, istate[:, :, 1]) - -# %% -p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, cg.c_x) - -# %% -#pcolormesh in Julia -# gn = TwoDGridNotes(grid); - -# gridmesh = [(i,j) for i in gn.x, j in gn.y]; -# mesh.x = [i for i in gn.x, j in gn.y]; -# mesh.y = [j for i in gn.x, j in gn.y]; -# mesh.x = mesh.x[1:3:end, 1:3:end]; -# mesh.y = mesh.y[1:3:end, 1:3:end]; - -# %% -# %% - -p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, wave_simulation.model.State[:, :, 2]) - -# plt.quiver!(p1, mesh.x / 1e3, mesh.y / 1e3, quiver=(wave_simulation.model.State[1:3:end, 1:3:end, 2] * 20, wave_simulation.model.State[1:3:end, 1:3:end, 3] * 20), color=:red, scale_unit=:data, label="wind") -# # scale_unit options: :width, :height, :x, :y, :xy, :data - -plt.contour(p1, gn.x / 1e3, gn.y / 1e3, u.(mesh.x, mesh.y, wave_simulation.model.clock.time), color="white") - -# # heatmap(wave_simulation.model.State[:, :, 2]) -# # heatmap(wave_simulation.model.State[:, :, 3]) - - -#sqrt( wave_simulation.model.winds.v.(mesh.x, mesh.y, 0.0)^2 + wave_simulation.model.winds.u.(mesh.x, mesh.y, 0.0)^2) - -# %% -Revise.retry() -wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, - winds=winds, - ODEsys=particle_system, - ODEsets=ODE_settings, # ODE_settings - ODEinit_type="wind_sea", # default_ODE_parameters - periodic_boundary=false, - boundary_type="same", - #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), - movie=true) - -wave_simulation = Simulation(wave_model, Δt=5minutes, stop_time=4hours)#1hours) -initialize_simulation!(wave_simulation) - -#reset_simulation!(wave_simulation, particle_initials=copy(wave_model.ODEdefaults)) - -fig, n = init_movie_2D_box_plot(wave_simulation, name_string= "Rotating Stationary Winds") - -#wave_simulation.stop_time += 1hour -N = 250 -record(fig, save_path*"T02_2D_totating_winds_nonper.gif", 1:N, framerate=10) do i - @info "Plotting frame $i of $N..." - #@time for _ = 1:10 - #run!(wave_simulation, store=false) - @info wave_simulation.model.clock - movie_time_step!(wave_simulation.model, wave_simulation.Δt) - #coupled_time_step!(ocean_simulation, ice_simulation) - #end - n[] = 1 -end diff --git a/tests/T04_2D_box_rotation.jl b/tests/T04_2D_box_rotation.jl index 43bd226..25f4896 100644 --- a/tests/T04_2D_box_rotation.jl +++ b/tests/T04_2D_box_rotation.jl @@ -22,12 +22,11 @@ import Oceananigans.Utils: prettytime using PiCLES.Architectures using GLMakie + using Revise using PiCLES.Operators.core_2D: GetGroupVelocity, speed using PiCLES.Plotting.movie: init_movie_2D_box_plot, init_movie_2D_box_plot_small -using Revise - # debugging: #using ProfileView diff --git a/tests/batch_join.jl b/tests/batch_join.jl deleted file mode 100644 index b3ff15c..0000000 --- a/tests/batch_join.jl +++ /dev/null @@ -1,88 +0,0 @@ -using DataFrames, DelimitedFiles, CSV - -# Defining helper functions - -function unit_dec(a) - unit=string(Int64(floor((a)))) - dec=string(Int64(floor(10*(a-floor((a)))))) - return unit*","*dec -end - -# Starting the merge - -parentPath = pwd()*"/plots/test_case_2/model_outputs" -mkdir(parentPath) -mkdir(parentPath*"/data") -mkdir(parentPath*"/plots") -# parentPath = "/home1/datahome/tprotin/Travail/PiCLES/PiCLES/plots/tests/paper/test_case_3/v3_half_cell" -println("------------ Reading the data from : "* parentPath * " ------------") - -nBatch = 10 -paths = [parentPath*"_batch"*string(i) for i in 1:nBatch] - -path = paths[1]*"/data/simu_infos.csv" -path2 = paths[1]*"/data/sigma.csv" -data, header = readdlm(path, ',', header=true) -data2, header2 = readdlm(path2, ',', header=true) - -simu_infos = DataFrame(data, vec(header)) -init_sigma_df = DataFrame(data2, vec(header2)) - -init_sigma = Matrix(init_sigma_df) -Nx = simu_infos.Nx[1] -Ny = simu_infos.Ny[1] -xmin = simu_infos.xmin[1] -xmax = simu_infos.xmax[1] -ymin = simu_infos.ymin[1] -ymax = simu_infos.ymax[1] -lne_source = simu_infos.lne_source[1] -c_x_source = simu_infos.c_x_source[1] -c_y_source = simu_infos.c_y_source[1] -x_source = simu_infos.x_source[1] -y_source = simu_infos.y_source[1] -angular_spread_source = simu_infos.angular_spread_source[1] -Δt = simu_infos.Δt[1] -stop_time = simu_infos.stop_time[1] - -nTimes = Int64(ceil(stop_time/Δt))+1 - -times = (0:(nTimes))*Δt -timesMinutes = times/60 - -timesMinutesString = unit_dec.(timesMinutes) - - -ParticleStates = DataFrame([[],[]],["times", "particleList"]) -MeshState = DataFrame([[],[]],["times", "mesh_state"]) - - -for i in 1:nTimes - temp_df1 = DataFrame([[],[],[],[],[],[]], ["id", "logE", "cx", "cy", "x", "y"]) - columnNames = ["Column"*string(Int64(i)) for i in 1:Nx] - temp_df2 = DataFrame(zeros(70,300), columnNames) - for j in 1:nBatch - path1 = paths[j]*"/data/particles_"*timesMinutesString[i]*".csv" - path2 = paths[j]*"/data/mesh_values_"*timesMinutesString[i]*".csv" - data1, header1 = readdlm(path1, ',', header=true) - data2, header2 = readdlm(path2, ',', header=true) - - read_df1 = DataFrame(data1, vec(header1)) - read_df2 = DataFrame(data2, vec(header2)) - - append!(temp_df1, read_df1) - temp_df2 = read_df2 .+ temp_df2 - end - temp_df1 = DataFrame([[timesMinutes[i]], [temp_df1]], ["times", "particleList"]) - temp_df2 = DataFrame([[timesMinutes[i]], [temp_df2]], ["times", "mesh_state"]) - append!(ParticleStates, temp_df1) - append!(MeshState, temp_df2) - - time = ParticleStates[end,"times"]*60 - println(time) - - sec=string(Int64(floor((time)/60))) - dec=string(Int64(floor(10*(time/60-floor((time)/60))))) - - CSV.write(parentPath*"/data/mesh_values_"*sec*","*dec*".csv", temp_df2[end,"mesh_state"]) - CSV.write(parentPath*"/data/particles_"*sec*","*dec*".csv", temp_df1[end,"particleList"]) -end diff --git a/tests/test_case_1.jl b/tests/test_case_1.jl index ce3a685..4fae8c5 100644 --- a/tests/test_case_1.jl +++ b/tests/test_case_1.jl @@ -111,7 +111,7 @@ wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, 0 1e-50 0 0; 0 0 1e-50 0 0 0 0 1e-50], - n_particles_launch=150000 + n_particles_launch=1500 ) wave_simulation = Simulation(wave_model, Δt=0.75minutes, stop_time=60minutes) From 975cf7b4b46fc6c13a8870ac7f42b3330184b522 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Tue, 7 Oct 2025 15:44:27 +0200 Subject: [PATCH 19/37] fixed test_case_1 --- tests/test_case_1.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_case_1.jl b/tests/test_case_1.jl index 4fae8c5..ce3a685 100644 --- a/tests/test_case_1.jl +++ b/tests/test_case_1.jl @@ -111,7 +111,7 @@ wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, 0 1e-50 0 0; 0 0 1e-50 0 0 0 0 1e-50], - n_particles_launch=1500 + n_particles_launch=150000 ) wave_simulation = Simulation(wave_model, Δt=0.75minutes, stop_time=60minutes) From e0f9f91a111e4acd4b7e9894eeb0793512a65087 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Tue, 7 Oct 2025 15:55:45 +0200 Subject: [PATCH 20/37] removed any reference to point source in Simulations.jl and run.jl --- src/Simulations/Simulations.jl | 2 +- src/Simulations/run.jl | 47 ---------------------------------- 2 files changed, 1 insertion(+), 48 deletions(-) diff --git a/src/Simulations/Simulations.jl b/src/Simulations/Simulations.jl index 016d86a..43faaea 100644 --- a/src/Simulations/Simulations.jl +++ b/src/Simulations/Simulations.jl @@ -3,7 +3,7 @@ module Simulations export Simulation export StateStore, CashStore, state_store, init_state_store!, push_state_to_storage!, AbstractStore, convert_store_to_tuple export add_winds_forcing_to_store!, reset_state_store!, show_stored_data, close_store!, EmptyStore, StateStore -export run!, reset_simulation!, initialize_simulation!, initialize_wave_sources! +export run!, reset_simulation!, initialize_simulation! export convert_store_to_tuple using ..Architectures: AbstractStore diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index 0961989..4f0c01a 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -173,53 +173,6 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) end # do time step - #launch new batch of particles from cyclic launch - if length(sim.model.PointSourceList) > 0 - for k in 1:length(sim.model.PointSourceList) - currentParticle = sim.model.PointSourceList[k].particleLaunch - currentFirstTimeLaunched = sim.model.PointSourceList[k].firstTimeLaunched - period = sqrt(sim.model.grid.dx*sim.model.grid.dy - / - (currentParticle.c̄_x^2+currentParticle.c̄_y^2)) - - t = sim.model.ParticleCollection[end].ODEIntegrator.t - #computing how many batches of particles have to be launched - timePrevLaunch = t >= currentFirstTimeLaunched ? t - (t - currentFirstTimeLaunched)%period : -1.0 - nBatch = 0 - - while timePrevLaunch > sim.model.ParticleCollection[end].ODEIntegrator.t - sim.Δt - nBatch+=1 - timePrevLaunch-=period - end - - for nB in 1:nBatch - i = Int64(floor((sim.model.PointSourceList[k].particleLaunch.x - sim.model.grid.xmin) / sim.model.grid.dx)) + 1 - j = Int64(floor((sim.model.PointSourceList[k].particleLaunch.y - sim.model.grid.ymin) / sim.model.grid.dy)) + 1 - n_part = sim.model.n_particles_launch - - defaults_temp = deepcopy(sim.model.PointSourceList[k].particleLaunch) - defaults_temp.lne -= log(n_part) - basePart = SeedParticle(sim.model.State, - (i,j), sim.model.ODEsystem, defaults_temp, - sim.model.ODEsettings,gridnotes, sim.model.winds, - sim.model.ODEsettings.timestep, sim.model.boundary, - sim.model.periodic_boundary) - for _ in 1:n_part - delta_phi = rand() * defaults_temp.angular_σ - 0.5*defaults_temp.angular_σ - c_x = defaults_temp.c̄_x * cos(delta_phi) - defaults_temp.c̄_y * sin(delta_phi) - c_y = defaults_temp.c̄_x * sin(delta_phi) + defaults_temp.c̄_y * cos(delta_phi) - push!(sim.model.ParticleCollection, deepcopy(basePart)) - sim.model.ParticleCollection[end].ODEIntegrator.u[2] = c_x - sim.model.ParticleCollection[end].ODEIntegrator.u[3] = c_y - sim.model.ParticleCollection[end].ODEIntegrator.uprev[2] = c_x - sim.model.ParticleCollection[end].ODEIntegrator.uprev[3] = c_y - sim.model.ParticleCollection[end].ODEIntegrator.uprev2[2] = c_x - sim.model.ParticleCollection[end].ODEIntegrator.uprev2[3] = c_y - end - end - #@info "nBatch = ", nBatch - end - end time_step!(sim.model, sim.Δt, debug=debug) if debug & (length(sim.model.FailedCollection) > 0) From 61d2c682ff94541c6a1732399ff8f86ae35b4926 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Tue, 7 Oct 2025 15:57:00 +0200 Subject: [PATCH 21/37] completed previous commit --- src/Simulations/run.jl | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index 4f0c01a..e3c4bdd 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -222,15 +222,6 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) end -function initialize_wave_sources!(sim::Simulation, list::Array{Any,1}) - if sim.verbose - @info "init particle sources..." - end - - sim.model.PointSourceList = list - - nothing -end """ initialize_simulation!(sim::Simulation) @@ -444,31 +435,6 @@ function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose:: model.periodic_boundary)) end end - - if length(model.PointSourceList) != 0 - @info "launching cyclic point source particles" - for k in 1:length(model.PointSourceList) - if model.PointSourceList[k].firstTimeLaunched != 0.0 - i = Int64(floor((model.PointSourceList[k].particleLaunch.x - model.grid.xmin) / model.grid.dx)) + 1 - j = Int64(floor((model.PointSourceList[k].particleLaunch.y - model.grid.ymin) / model.grid.dy)) + 1 - n_part = model.n_particles_launch - for _ in 1:n_part - defaults_temp = deepcopy(model.PointSourceList[k].particleLaunch) - delta_phi = rand() * defaults_temp.angular_σ - 0.5*defaults_temp.angular_σ - c_x = defaults_temp.c̄_x * cos(delta_phi) - defaults_temp.c̄_y * sin(delta_phi) - c_y = defaults_temp.c̄_x * sin(delta_phi) + defaults_temp.c̄_y * cos(delta_phi) - defaults_temp.lne += -log(n_part) - defaults_temp.c̄_x = c_x - defaults_temp.c̄_y = c_y - push!(ParticleCollection, SeedParticle(model.State, - (i,j), model.ODEsystem, defaults_temp, - model.ODEsettings,gridnotes, model.winds, - model.ODEsettings.timestep, model.boundary, - model.periodic_boundary)) - end - end - end - end nothing end From 4bcd2010fd9843cf9e14c844d19606d67ef760d5 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Tue, 7 Oct 2025 16:26:52 +0200 Subject: [PATCH 22/37] fixed ParticleSystem.jl and made ParticleInCell.jl compatible in both versions --- src/ParticleInCell.jl | 56 +++++++++++++++++++++++--- src/ParticleSystems/ParticleSystems.jl | 2 +- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/ParticleInCell.jl b/src/ParticleInCell.jl index 1ca2cd2..b0d4699 100644 --- a/src/ParticleInCell.jl +++ b/src/ParticleInCell.jl @@ -305,8 +305,6 @@ end ## very general verion 2D function push_to_grid!(grid::Matrix{Float64}, - particlesAtNode::Array{Array{Array{Any,1},1},1}, - PI::AbstractParticleInstance, charge::Float64, index_pos::Tuple{Int, Int}, weights::Tuple{Float64, Float64}, @@ -317,6 +315,30 @@ function push_to_grid!(grid::Matrix{Float64}, end +## most recent version 2D - not with Boundary types +function push_to_grid!(grid::StateTypeL1, + charge::CC, + index_pos::II, + weights::WW, + Nx::Int, Ny::Int, + periodic::Bool = true) where {CC<:Union{Vector{Float64},SVector{3,Float64},MVector{3,AbstractFloat}}, + II<:Union{Tuple{Int,Int},SVector{2,Int64}}, + WW<:Union{Tuple{Float64,Float64},SVector{2,Float16}}} + if periodic + grid[ wrap_index!(index_pos[1], Nx) , wrap_index!(index_pos[2], Ny), : ] += weights[1] * weights[2] * charge + else + if sum( test_domain(index_pos, Nx, Ny) ) != 2 + # position outside of domain + return + else + # position is inside the domain + grid[ index_pos[1] , index_pos[2], : ] += weights[1] * weights[2] * charge + end + end + +end + + ## most recent version 2D - not with Boundary types function push_to_grid!(grid::SharedArray{Float64, 3}, particlesAtNode::Array{Array{Array{Any,1},1},1}, @@ -480,6 +502,18 @@ end # ----------------------- wrappers ----------------------- # wrapping over vectors of charges, index positions and weights +function push_to_grid!(grid::StateTypeL1, + charge::Vector{Float64}, + index_pos::Vector{Tuple{Int, Int}}, + weights::Vector{Tuple{Float64, Float64}}, + Nx::Int, Ny::Int, + periodic::Bool=true) + #@info "this is version D" + for (i, w) in zip(index_pos, weights) + push_to_grid!(grid, charge , i, w , Nx, Ny, periodic) + end +end + function push_to_grid!(grid::SharedArray{Float64, 3}, particlesAtNode::Array{Array{Array{Any,1},1},1}, PI::AbstractParticleInstance, @@ -561,6 +595,20 @@ end ###### 1D versions #### # wrapper over 1D Vecors of chanegs and (nested) index positions and weights +function push_to_grid!(grid::SharedMatrix{Float64}, + charge::CC, + index_pos::Vector{Any}, + weights::Vector{Any}, + Nx::Int, + periodic::Bool=true) where CC <: Union{Vector{Float64}, SVector{Float64}} + #@info "this is version C" + for (im, wm, c) in zip(index_pos, weights, charge) + for (i, w) in zip(im, wm) + push_to_grid!(grid, c, i, w, Nx, periodic) + end + end +end + function push_to_grid!(grid::SharedMatrix{Float64}, particlesAtNode::Array{Array{Array{Any,1},1},1}, PI::AbstractParticleInstance, @@ -581,8 +629,6 @@ end # multiple index positions and 1 charge function push_to_grid!(grid::MM, - particlesAtNode::Array{Array{Array{Any,1},1},1}, - PI::AbstractParticleInstance, charge::CC, index_pos::Vector{Int}, weights::Vector{Float64}, @@ -614,8 +660,6 @@ end # only 1 index position and 1 charge function push_to_grid!(grid::MM, - particlesAtNode::Array{Array{Array{Any,1},1},1}, - PI::AbstractParticleInstance, charge::Float64, index_pos::Int, weights::Float64, diff --git a/src/ParticleSystems/ParticleSystems.jl b/src/ParticleSystems/ParticleSystems.jl index adc719e..10264b4 100644 --- a/src/ParticleSystems/ParticleSystems.jl +++ b/src/ParticleSystems/ParticleSystems.jl @@ -1,6 +1,6 @@ module ParticleSystems -export particle_waves_v3, particle_waves_v3beta, particle_waves_v4, particle_waves_v5, particle_waves_v5 +export particle_waves_v3, particle_waves_v3beta, particle_waves_v4, particle_waves_v5, particle_waves_v6 # include("particle_waves_v3beta.jl") # include("particle_waves_v3.jl") From 15f9ebb38bc8674ad268e717dbe85b623f41df34 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Tue, 7 Oct 2025 16:45:29 +0200 Subject: [PATCH 23/37] fixed mapping_2D.jl --- src/Operators/mapping_2D.jl | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index d441372..507dcf8 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -15,11 +15,9 @@ using ...custom_structures: ParticleInstance1D, ParticleInstance2D, MarkedPartic using ..core_2D_spread: GetParticleEnergyMomentum, GetVariablesAtVertex, Get_u_FromShared, ResetParticleValues, ParticleDefaults, InitParticleInstance -using ...Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, AbstractODESettings, StateTypeL1 +using ...Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, AbstractODESettings, StateTypeL1, Abstract2DModel using ...Architectures: Grid2D, CartesianGrid, CartesianGridStatistics, CartesianGrid2D, CartesianGrid1D, AbstractGridStatistics, AbstractGrid, StandardRegular2D_old, MeshGrids, MeshGridStatistics - -using ...Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, AbstractODESettings, Abstract2DModel ###### remeshing routines ############ @@ -222,10 +220,6 @@ function advance!(PI::AbstractParticleInstance, @info "position or Energy is nan, reset" @info PI.position_ij @show PI - @info PI.ODEIntegrator.uprev - @info PI.ODEIntegrator.uprev2 - - test.test t_end = t_start + DT winds_start = convert( Tuple{Float64,Float64}, @@ -307,7 +301,7 @@ function remesh!(i::Int64, j::Int64, model::Abstract2DModel, DT::Float64) ti = model.clock.time grid = model.grid - x = grid.xmin + grid.dx*(i-1) # A MODIFIER ??? Peut-etre changer i pour i-1 pour mettre bien à 0, pareil pour j + x = grid.xmin + grid.dx*(i-1) y = grid.ymin + grid.dy*(j-1) winds_i::Tuple{Float64,Float64} = winds.u(x, y, ti), winds.v(x, y, ti) @@ -425,7 +419,7 @@ function remesh!(i::Int64, j::Int64, model::Abstract2DModel, DT::Float64) ti = model.clock.time grid = model.grid - x = grid.xmin + grid.dx*(i-1) # A MODIFIER ??? Peut-etre changer i pour i-1 pour mettre bien à 0, pareil pour j + x = grid.xmin + grid.dx*(i-1) y = grid.ymin + grid.dy*(j-1) winds_i::Tuple{Float64,Float64} = winds.u(x, y, ti), winds.v(x, y, ti) From 14737319316c6199785e044a7a1334af5ad2997f Mon Sep 17 00:00:00 2001 From: tomprotin Date: Tue, 7 Oct 2025 16:52:38 +0200 Subject: [PATCH 24/37] fixed TimeSteppers.jl --- src/Operators/TimeSteppers.jl | 38 ++++------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/src/Operators/TimeSteppers.jl b/src/Operators/TimeSteppers.jl index 4b5f54d..5f2ca8e 100644 --- a/src/Operators/TimeSteppers.jl +++ b/src/Operators/TimeSteppers.jl @@ -229,40 +229,10 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb elseif model.angular_spreading_type == "nonparametric" # This next part needs to change - - """ - i=1 - particlesToBeReset = [] - particlesToBeResetIndex = [] - - for _ in 1:length(model.ParticleCollection) - pos_ij = model.ParticleCollection[i].position_ij - big_enough = model.State[pos_ij[1], pos_ij[2],2]^2+model.State[pos_ij[1], pos_ij[2],3]^2>model.minimal_state[2] - if model.ParticleCollection[i].boundary || ~big_enough - i=i+1 - else - if !(model.ParticleCollection[i].position_ij in particlesToBeResetIndex) - push!(particlesToBeResetIndex, model.ParticleCollection[i].position_ij) - end - deleteat!(model.ParticleCollection, i) - end - end - """ - - """ - @threads for a_particle in model.ParticleCollection - mapping_2D.remesh!(a_particle, model.State, - model.winds, model.clock.time, - model.ODEsettings, Δt, - model.minimal_particle, - model.minimal_state, - model.ODEdefaults) - end - """ - + nPreviousParticles = 0 model.ParticlePool = [] - + @threads for (i,j) in [(i,j) for i in 1:model.grid.Nx for j in 1:model.grid.Ny] locallen = length(model.ParticlesAtNode[i][j]) nPreviousParticles += locallen @@ -272,7 +242,7 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb # newodeint=init(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.t,[deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[1]), deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[2]), deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[3]), deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[4]), deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[5]), deepcopy(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[6])]) # println(newodeint) # println() - + z_init = ParticleDefaults(Upart[1],Upart[2],Upart[3],Upart[4],Upart[5],Upart[6]) newpart=InitParticleInstance(model.ODEsystem,z_init,model.ODEsettings,(i,j),false,true) push!(model.ParticlePool, [newpart, i, j, exp(model.ParticlesAtNode[i][j][k][3].ODEIntegrator.u[1])*model.ParticlesAtNode[i][j][k][1]]) @@ -293,7 +263,7 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb particlesDrawn = rand(a, nNewParticles) #new_energy_tot = sum([energiesNormed[k] for k in particlesDrawn]) #energy_factor = totEnergyDomain[1] / new_energy_tot - + i = 1 j = 0 counter = 0 From 70ee4c02220054846fc2c2c1d1306d6de1e18d49 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Tue, 7 Oct 2025 16:57:56 +0200 Subject: [PATCH 25/37] removed references to point sources in GeometricalOpticsModels.jl --- src/Models/GeometricalOpticsModels.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Models/GeometricalOpticsModels.jl b/src/Models/GeometricalOpticsModels.jl index b8252c8..68744f8 100644 --- a/src/Models/GeometricalOpticsModels.jl +++ b/src/Models/GeometricalOpticsModels.jl @@ -45,7 +45,6 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, Pan, PCollection, PPool, - PtSrcList, FPC, Ovar, Osys, @@ -77,7 +76,6 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, ParticlesAtNode::Pan # list of the particles to regrid at each node ParticleCollection::PCollection # Collection (list) of Particles ParticlePool::PPool # Pool of particles (used for non parametric mode) - PointSourceList::PtSrcList # List of all the point sources of waves FailedCollection::FPC # Collection (list) of Particles that failed to integrate ODEvars::Ovar # list of variables in ODE system, have type Num from OrdinaryDiffEq and ModelingToolkit @@ -199,7 +197,6 @@ function GeometricalOptics(; grid::TwoDGrid, end ParticlePool = Array{Any,1}() end - PointSourceList = [] if ODEinit_type isa ParticleDefaults2D ODEdefaults = ODEinit_type @@ -281,7 +278,6 @@ function GeometricalOptics(; grid::TwoDGrid, ParticlesAtNode, ParticleCollection, ParticlePool, - PointSourceList, FailedCollection, ODEvars, ODEsys, From 18087f8dea5fea2190e8f85083374c1286eca89e Mon Sep 17 00:00:00 2001 From: tomprotin Date: Tue, 9 Dec 2025 14:37:02 +0100 Subject: [PATCH 26/37] moved SIR_analysis.jl to analysis/SIR_analysis.jl --- SIR_analysis.jl => analysis/SIR_analysis.jl | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename SIR_analysis.jl => analysis/SIR_analysis.jl (100%) diff --git a/SIR_analysis.jl b/analysis/SIR_analysis.jl similarity index 100% rename from SIR_analysis.jl rename to analysis/SIR_analysis.jl From 2609a1cb306fededac8763ad7b41dc4eaa37c143 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Tue, 9 Dec 2025 14:59:07 +0100 Subject: [PATCH 27/37] changed .gitignore --- .gitignore | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.gitignore b/.gitignore index 2691fd8..9455ad4 100644 --- a/.gitignore +++ b/.gitignore @@ -26,17 +26,6 @@ Manifest.toml config/config.json --temp/* -Project_save.toml -package_list.txt -plots/* -tests/test_boundary_effect.jl -tests/test_debug.jl -Manifest2.toml -paper1_final/* .DS_Store -test_case_*.html -test_case_3_batch1_copy.jl .ipynb* - -Description algorithme PiCLES/* From 244a6907c19c12dfb18a84bbc3356f122ead9dd9 Mon Sep 17 00:00:00 2001 From: mochell Date: Wed, 31 Dec 2025 11:59:04 -0800 Subject: [PATCH 28/37] some other local changes --- .gitignore | 8 +- Project.toml | 29 +++++- src/Models/GeometricalOpticsModels.jl | 4 +- src/Operators/mapping_2D.jl | 22 +---- src/ParticleInCell.jl | 130 +++++++++++++------------- src/Simulations/run.jl | 7 +- 6 files changed, 103 insertions(+), 97 deletions(-) diff --git a/.gitignore b/.gitignore index 2691fd8..065e22b 100644 --- a/.gitignore +++ b/.gitignore @@ -25,15 +25,19 @@ Manifest.toml config/config.json +plots/* +.DS_Store + +# Tom's files --temp/* Project_save.toml package_list.txt -plots/* + tests/test_boundary_effect.jl tests/test_debug.jl Manifest2.toml paper1_final/* -.DS_Store + test_case_*.html test_case_3_batch1_copy.jl diff --git a/Project.toml b/Project.toml index e7fb882..b178a39 100644 --- a/Project.toml +++ b/Project.toml @@ -5,33 +5,52 @@ version = "0.1.0-DEV" [deps] ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63" +Atom = "c52e3926-4ff0-5f6e-af25-54175e0327b1" BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +Callbacks = "db1e321a-d383-57b4-a664-0144fd54e973" +ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" -DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" +Dierckx = "39dd38d3-220a-591b-8e3c-4c3a8c710a94" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" +GEMPIC = "b6d65c3a-4a4e-11e9-25d0-d309dc85ddeb" GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" GeoMakie = "db073c08-6b98-4ee5-b6a4-5efafb3259c6" HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" +Juno = "e5e0dc1b-0480-54bc-9374-aad01c23163d" +LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" +Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" Oceananigans = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09" +OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +Pandas = "eadc2687-ae89-51f9-a5d9-86b5a6373a9c" Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" +PkgTemplates = "14b8a8f1-9102-5b29-a752-f990bacb7fe1" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +ProfileView = "c46f51b8-102a-5cf2-8d2c-8597cb0e0da7" +PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" +PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" SharedArrays = "1a1011a3-84de-559e-8e89-a11a2f7dc383" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" -StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" \ No newline at end of file +StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" +UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" +WebIO = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29" + +[compat] +julia = "1.10.0" + +[extras] +CPUSummary = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" diff --git a/src/Models/GeometricalOpticsModels.jl b/src/Models/GeometricalOpticsModels.jl index 68744f8..2e1db73 100644 --- a/src/Models/GeometricalOpticsModels.jl +++ b/src/Models/GeometricalOpticsModels.jl @@ -129,8 +129,8 @@ end """ -WaveGrowth2D(; grid, winds, ODEsys, ODEvars, layers, clock, ODEsets, ODEdefaults, currents, periodic_boundary, CBsets) -This is the constructor for the WaveGrowth2D model. The inputs are: +GeometricalOptics(; grid, winds, ODEsys, ODEvars, layers, clock, ODEsets, ODEdefaults, currents, periodic_boundary, CBsets) + This is the constructor for the GeometricalOptics model. The inputs are: grid : the grid used in the model, winds : the wind interpolation function here only 1D, ODEsys : the ODE system used in the model, diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index 507dcf8..545bd92 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -38,21 +38,6 @@ S Shared array where particles are stored G (TwoDGrid) Grid that defines the nodepositions """ -function ParticleToNode!(PI::AbstractParticleInstance, particlesAtNode::Array{Array{Array{Any,1},1},1}, S::SharedArray, G::TwoDGrid, periodic_boundary::Bool) - - #u[4], u[5] are the x and y positions of the particle - #index_positions, weights = PIC.compute_weights_and_index(G, PI.ODEIntegrator.u[4], PI.ODEIntegrator.u[5]) - weights_and_index = PIC.compute_weights_and_index_mininal(G, PI.ODEIntegrator.u[4], PI.ODEIntegrator.u[5]) - - #ui[1:2] .= PI.position_xy - u_state = GetParticleEnergyMomentum(PI.ODEIntegrator.u) - #@show u_state - - #PIC.push_to_grid!(S, particlesAtNode, PI, u_state , index_positions, weights, G.Nx, G.Ny , periodic_boundary) - PIC.push_to_grid!(S, particlesAtNode, PI, u_state , weights_and_index, G.Nx, G.Ny , periodic_boundary) - nothing -end - function ParticleToNode!(PI::AbstractParticleInstance, S::StateTypeL1, G::TwoDGrid, periodic_boundary::Bool) #u[4], u[5] are the x and y positions of the particle @@ -136,8 +121,7 @@ end advance!(PI::AbstractParticleInstance, S::SharedMatrix{Float64}, G::TwoDGrid, DT::Float64) """ function advance!(PI::AbstractParticleInstance, - particlesAtNode::Array{Array{Array{Any,1},1},1}, - S::SharedArray, + S::StateTypeL1, Failed::Vector{AbstractMarkedParticleInstance}, Grid::Union{Grid2D,MeshGrids}, winds::NamedTuple{(:u, :v)}, @@ -259,7 +243,7 @@ function advance!(PI::AbstractParticleInstance, #if PI.ODEIntegrator.u[1] > -13.0 #ODEs.log_energy_minimum # the minimum enerçy is distributed to 4 neighbouring particles if PI.on - ParticleToNode!(PI, particlesAtNode, S, Grid, periodic_boundary) + ParticleToNode!(PI, S, Grid, periodic_boundary) end #return PI @@ -433,7 +417,7 @@ end - If Node value is okey, it is converted to state variable and pushed to particle. - The particle position is set to the node positions """ -function NodeToParticle!(PI::AbstractParticleInstance, S::SharedArray, +function NodeToParticle!(PI::AbstractParticleInstance, S::StateTypeL1, wind_tuple::Tuple{Float64,Float64}, grid_stats::MeshGridStatistics, minimal_state::Vector{Float64}, diff --git a/src/ParticleInCell.jl b/src/ParticleInCell.jl index b0d4699..bef1e2d 100644 --- a/src/ParticleInCell.jl +++ b/src/ParticleInCell.jl @@ -10,7 +10,7 @@ using ..custom_structures: wni, N_Periodic, N_NonPeriodic, N_TripolarNorth # %% using ..ParticleMesh -using ...Architectures: AbstractParticleInstance +#using ...Architectures: AbstractParticleInstance # Tolerance for comparison of real numbers: set it here! # Set parameters @@ -320,8 +320,8 @@ function push_to_grid!(grid::StateTypeL1, charge::CC, index_pos::II, weights::WW, - Nx::Int, Ny::Int, - periodic::Bool = true) where {CC<:Union{Vector{Float64},SVector{3,Float64},MVector{3,AbstractFloat}}, + Nx::Int, Ny::Int, + periodic::Bool=true) where {CC<:Union{Vector{Float64},SVector{3,Float64},MVector{3,AbstractFloat}}, II<:Union{Tuple{Int,Int},SVector{2,Int64}}, WW<:Union{Tuple{Float64,Float64},SVector{2,Float16}}} if periodic @@ -339,29 +339,29 @@ function push_to_grid!(grid::StateTypeL1, end -## most recent version 2D - not with Boundary types -function push_to_grid!(grid::SharedArray{Float64, 3}, - particlesAtNode::Array{Array{Array{Any,1},1},1}, - PI::AbstractParticleInstance, - charge::Vector{Float64}, - index_pos::Tuple{Int, Int}, - weights::Tuple{Float64, Float64}, - Nx::Int, Ny::Int, - periodic::Bool = true) - if periodic - grid[ wrap_index!(index_pos[1], Nx) , wrap_index!(index_pos[2], Ny), : ] += weights[1] * weights[2] * charge - else - if sum( test_domain(index_pos, Nx, Ny) ) != 2 - # position outside of domain - return - else - # position is inside the domain - push!(particlesAtNode[index_pos[1]][index_pos[2]], [weights[1] * weights[2], charge[4], PI]) - grid[ index_pos[1] , index_pos[2], 1:3 ] += weights[1] * weights[2] * charge[1:3] - end - end +# ## most recent version 2D - not with Boundary types +# function push_to_grid!(grid::SharedArray{Float64, 3}, +# particlesAtNode::Array{Array{Array{Any,1},1},1}, +# PI::AbstractParticleInstance, +# charge::Vector{Float64}, +# index_pos::Tuple{Int, Int}, +# weights::Tuple{Float64, Float64}, +# Nx::Int, Ny::Int, +# periodic::Bool = true) +# if periodic +# grid[ wrap_index!(index_pos[1], Nx) , wrap_index!(index_pos[2], Ny), : ] += weights[1] * weights[2] * charge +# else +# if sum( test_domain(index_pos, Nx, Ny) ) != 2 +# # position outside of domain +# return +# else +# # position is inside the domain +# push!(particlesAtNode[index_pos[1]][index_pos[2]], [weights[1] * weights[2], charge[4], PI]) +# grid[ index_pos[1] , index_pos[2], 1:3 ] += weights[1] * weights[2] * charge[1:3] +# end +# end -end +# end # Abstract Boundary Version function push_to_grid!(grid::StateTypeL1, @@ -514,19 +514,19 @@ function push_to_grid!(grid::StateTypeL1, end end -function push_to_grid!(grid::SharedArray{Float64, 3}, - particlesAtNode::Array{Array{Array{Any,1},1},1}, - PI::AbstractParticleInstance, - charge::Vector{Float64}, - index_pos::Vector{Tuple{Int, Int}}, - weights::Vector{Tuple{Float64, Float64}}, - Nx::Int, Ny::Int, - periodic::Bool=true) - #@info "this is version D" - for (i, w) in zip(index_pos, weights) - push_to_grid!(grid, particlesAtNode, PI, charge , i, w , Nx, Ny, periodic) - end -end +# function push_to_grid!(grid::SharedArray{Float64, 3}, +# particlesAtNode::Array{Array{Array{Any,1},1},1}, +# PI::AbstractParticleInstance, +# charge::Vector{Float64}, +# index_pos::Vector{Tuple{Int, Int}}, +# weights::Vector{Tuple{Float64, Float64}}, +# Nx::Int, Ny::Int, +# periodic::Bool=true) +# #@info "this is version D" +# for (i, w) in zip(index_pos, weights) +# push_to_grid!(grid, particlesAtNode, PI, charge , i, w , Nx, Ny, periodic) +# end +# end #push_to_grid!(charges_grid, 1.0 , index_positions[3], weights[3] , grid2d.Nx , grid2d.Ny ) ## allocation optimized: @@ -551,18 +551,18 @@ end """ wrapper over FieldVector weight&index (wni), """ -function push_to_grid!(grid::SharedArray{Float64, 3}, - particlesAtNode::Array{Array{Array{Any,1},1},1}, - PI::AbstractParticleInstance, - charge::CC, - wni::FieldVector, - Nx::Int, Ny::Int, - periodic::Bool=true) where CC <: Union{Vector{Float64}, SVector{3, Float64}} - #@info "this is version D" - for (i, w) in construct_loop(wni) - push_to_grid!(grid,particlesAtNode, PI, charge, i, w, Nx, Ny, periodic) - end -end +# function push_to_grid!(grid::SharedArray{Float64, 3}, +# particlesAtNode::Array{Array{Array{Any,1},1},1}, +# PI::AbstractParticleInstance, +# charge::CC, +# wni::FieldVector, +# Nx::Int, Ny::Int, +# periodic::Bool=true) where CC <: Union{Vector{Float64}, SVector{3, Float64}} +# #@info "this is version D" +# for (i, w) in construct_loop(wni) +# push_to_grid!(grid,particlesAtNode, PI, charge, i, w, Nx, Ny, periodic) +# end +# end function push_to_grid!(grid::StateTypeL1, charge::CC, @@ -609,21 +609,21 @@ function push_to_grid!(grid::SharedMatrix{Float64}, end end -function push_to_grid!(grid::SharedMatrix{Float64}, - particlesAtNode::Array{Array{Array{Any,1},1},1}, - PI::AbstractParticleInstance, - charge::CC, - index_pos::Vector{Any}, - weights::Vector{Any}, - Nx::Int, - periodic::Bool=true) where CC <: Union{Vector{Float64}, SVector{Float64}} - #@info "this is version C" - for (im, wm, c) in zip(index_pos, weights, charge) - for (i, w) in zip(im, wm) - push_to_grid!(grid, particlesAtNode, PI, c, i, w, Nx, periodic) - end - end -end +# function push_to_grid!(grid::SharedMatrix{Float64}, +# particlesAtNode::Array{Array{Array{Any,1},1},1}, +# PI::AbstractParticleInstance, +# charge::CC, +# index_pos::Vector{Any}, +# weights::Vector{Any}, +# Nx::Int, +# periodic::Bool=true) where CC <: Union{Vector{Float64}, SVector{Float64}} +# #@info "this is version C" +# for (im, wm, c) in zip(index_pos, weights, charge) +# for (i, w) in zip(im, wm) +# push_to_grid!(grid, particlesAtNode, PI, c, i, w, Nx, periodic) +# end +# end +# end diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index e3c4bdd..7660bee 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -160,8 +160,6 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) end end - gridnotes = TwoDGridNotes(sim.model.grid) - while sim.running @@ -207,6 +205,7 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) sim.running = sim.stop_time >= sim.model.clock.time ? true : false if sim.model.plot_steps + gridnotes = TwoDGridNotes(sim.model.grid) plot_state_and_error_points(sim, gridnotes) sec=string(Int64(floor((sim.model.clock.time)/60))) dec=string(Int64(floor(10*(sim.model.clock.time/60-floor((sim.model.clock.time)/60))))) @@ -297,7 +296,7 @@ initialize the model.ParticleCollection based on the model.grid and the defaults If defaults is nothing, then the model.ODEdev is used. usually the initilization uses wind constitions to seed the particles. """ -function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose::Bool=false) where {PP<:Union{ParticleDefaults,Array{Any,1},Nothing}} +function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose::Bool=false) where {PP<:Union{ParticleDefaults1D,ParticleDefaults2D,Nothing}} #defaults = isnothing(defaults) ? model.ODEdev : defaults if verbose @info "seed PiCLES ... \n" @@ -457,7 +456,7 @@ initialize the model.ParticleCollection based on the model.grid and the defaults If defaults is nothing, then the model.ODEdev is used. usually the initilization uses wind constitions to seed the particles. """ -function init_particles!(model::Abstract1DModel; defaults::PP=nothing, verbose::Bool=false) where {PP<:Union{ParticleDefaults,Nothing}} +function init_particles!(model::Abstract1DModel; defaults::PP=nothing, verbose::Bool=false) where {PP<:Union{ParticleDefaults1D,ParticleDefaults2D,Nothing}} #defaults = isnothing(defaults) ? model.ODEdev : defaults if verbose @info "seed PiCLES ... \n" From 04d984abf55614d922f1e9dd2bbcc76df8ce8973 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Thu, 8 Jan 2026 16:26:32 +0100 Subject: [PATCH 29/37] created a new abstract class for the stochastic model --- analysis/SIR_analysis.jl | 2 +- src/Architectures.jl | 1 + src/Models/GeometricalOpticsModels.jl | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/analysis/SIR_analysis.jl b/analysis/SIR_analysis.jl index 6902aa7..59c77e4 100644 --- a/analysis/SIR_analysis.jl +++ b/analysis/SIR_analysis.jl @@ -199,7 +199,7 @@ function pearson(data, predicted) end ## Reading the data -localpath = pwd() +localpath = pwd()*"/.." # parentPath = localpath * "/plots/tests/paper/test_case_1/v2_pi" # parentPath = localpath * "/plots/tests/paper/test_case_2_local/v2_pi_4" diff --git a/src/Architectures.jl b/src/Architectures.jl index f1596a9..11205b9 100644 --- a/src/Architectures.jl +++ b/src/Architectures.jl @@ -53,6 +53,7 @@ abstract type AbstractModel{TS} end abstract type Abstract1DModel <: AbstractModel{Nothing} end abstract type Abstract2DModel <: AbstractModel{Nothing} end +abstract type Abstract2DStochasticModel <: Abstract2DModel end #All posiible types of a single-layer StateVectors StateTypeL1 = Union{SharedArray{Float64,3},MArray} diff --git a/src/Models/GeometricalOpticsModels.jl b/src/Models/GeometricalOpticsModels.jl index 68744f8..b5d6347 100644 --- a/src/Models/GeometricalOpticsModels.jl +++ b/src/Models/GeometricalOpticsModels.jl @@ -64,7 +64,7 @@ mutable struct GeometricalOptics{Grid<:AbstractGrid, nPart, wnds, cur, - Mstat} <: Abstract2DModel where {Mstat<:Union{Nothing,stat}, PCollection<:Union{Vector,Array}} + Mstat} <: Abstract2DStochasticModel where {Mstat<:Union{Nothing,stat}, PCollection<:Union{Vector,Array}} #Union{Vector,DArray} grid::Grid layers::Lay # number of layers used in the model, 1 is eneough From 5a78d35e3b13dfb1828777f0ae8f99d00e768107 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Fri, 9 Jan 2026 14:18:06 +0100 Subject: [PATCH 30/37] first modifications to adapt the code to the new stochastic model structure --- src/Architectures.jl | 2 +- src/Operators/mapping_2D.jl | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Architectures.jl b/src/Architectures.jl index 11205b9..b60426a 100644 --- a/src/Architectures.jl +++ b/src/Architectures.jl @@ -4,7 +4,7 @@ using SharedArrays using StaticArrays -export AbstractGrid, AbstractODESettings, AbstractParticleInstance, AbstractMarkedParticleInstance, Abstract1DModel, Abstract2DModel, AbstractModel, AbstractStore, AbstractParticleSystem, StateTypeL1, IDConstantsInstance, ScgConstantsInstance, CartesianGrid, CartesianGrid1D, CartesianGrid2D, TripolarGrid, Grid2D, MeshGrids, MeshGridStatistics +export AbstractGrid, AbstractODESettings, AbstractParticleInstance, AbstractMarkedParticleInstance, Abstract1DModel, Abstract2DModel, Abstract2DStochasticModel, AbstractModel, AbstractStore, AbstractParticleSystem, StateTypeL1, IDConstantsInstance, ScgConstantsInstance, CartesianGrid, CartesianGrid1D, CartesianGrid2D, TripolarGrid, Grid2D, MeshGrids, MeshGridStatistics export StandardRegular1D_old, StandardRegular2D_old diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index 507dcf8..16e914c 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -15,7 +15,7 @@ using ...custom_structures: ParticleInstance1D, ParticleInstance2D, MarkedPartic using ..core_2D_spread: GetParticleEnergyMomentum, GetVariablesAtVertex, Get_u_FromShared, ResetParticleValues, ParticleDefaults, InitParticleInstance -using ...Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, AbstractODESettings, StateTypeL1, Abstract2DModel +using ...Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, AbstractODESettings, StateTypeL1, Abstract2DModel, Abstract2DStochasticModel using ...Architectures: Grid2D, CartesianGrid, CartesianGridStatistics, CartesianGrid2D, CartesianGrid1D, AbstractGridStatistics, AbstractGrid, StandardRegular2D_old, MeshGrids, MeshGridStatistics ###### remeshing routines ############ @@ -296,7 +296,7 @@ end Wrapper function that does everything necessary to remesh the particles. - pushes the Node State to particle instance """ -function remesh!(i::Int64, j::Int64, model::Abstract2DModel, DT::Float64) +function remesh!(i::Int64, j::Int64, model::Abstract2DStochasticModel, DT::Float64) winds = model.winds ti = model.clock.time grid = model.grid @@ -315,7 +315,7 @@ Pushes node value to particle: - If Node value is okey, it is converted to state variable and pushed to particle. - The particle position is set to the node positions """ -function NodeToParticle!(i::Int64, j::Int64, x::Float64, y::Float64, model::Abstract2DModel, wind_tuple::Tuple{Float64,Float64}, DT::Float64) +function NodeToParticle!(i::Int64, j::Int64, x::Float64, y::Float64, model::Abstract2DStochasticModel, wind_tuple::Tuple{Float64,Float64}, DT::Float64) S = model.State minimal_particle = model.minimal_particle minimal_state = model.minimal_state From 32c400401dd4ad5e8f66749c20d76a6a66e64bc8 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Fri, 9 Jan 2026 16:00:40 +0100 Subject: [PATCH 31/37] changed Project.toml and made corrections to make the code work --- Project.toml | 4 ++ src/Operators/mapping_2D.jl | 19 +++++++- src/ParticleInCell.jl | 94 ++++++++++++++++++------------------- src/Simulations/run.jl | 32 ++++--------- 4 files changed, 78 insertions(+), 71 deletions(-) diff --git a/Project.toml b/Project.toml index b178a39..5d5a3b0 100644 --- a/Project.toml +++ b/Project.toml @@ -13,6 +13,8 @@ Callbacks = "db1e321a-d383-57b4-a664-0144fd54e973" ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" Dierckx = "39dd38d3-220a-591b-8e3c-4c3a8c710a94" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" @@ -28,6 +30,7 @@ JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" Juno = "e5e0dc1b-0480-54bc-9374-aad01c23163d" LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" Oceananigans = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09" @@ -37,6 +40,7 @@ Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" PkgTemplates = "14b8a8f1-9102-5b29-a752-f990bacb7fe1" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" ProfileView = "c46f51b8-102a-5cf2-8d2c-8597cb0e0da7" PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index f55daad..36758aa 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -38,6 +38,21 @@ S Shared array where particles are stored G (TwoDGrid) Grid that defines the nodepositions """ +function ParticleToNode!(PI::AbstractParticleInstance, particlesAtNode::Array{Array{Array{Any,1},1},1}, S::SharedArray, G::TwoDGrid, periodic_boundary::Bool) + + #u[4], u[5] are the x and y positions of the particle + #index_positions, weights = PIC.compute_weights_and_index(G, PI.ODEIntegrator.u[4], PI.ODEIntegrator.u[5]) + weights_and_index = PIC.compute_weights_and_index_mininal(G, PI.ODEIntegrator.u[4], PI.ODEIntegrator.u[5]) + + #ui[1:2] .= PI.position_xy + u_state = GetParticleEnergyMomentum(PI.ODEIntegrator.u) + #@show u_state + + #PIC.push_to_grid!(S, particlesAtNode, PI, u_state , index_positions, weights, G.Nx, G.Ny , periodic_boundary) + PIC.push_to_grid!(S, particlesAtNode, PI, u_state , weights_and_index, G.Nx, G.Ny , periodic_boundary) + nothing +end + function ParticleToNode!(PI::AbstractParticleInstance, S::StateTypeL1, G::TwoDGrid, periodic_boundary::Bool) #u[4], u[5] are the x and y positions of the particle @@ -121,6 +136,7 @@ end advance!(PI::AbstractParticleInstance, S::SharedMatrix{Float64}, G::TwoDGrid, DT::Float64) """ function advance!(PI::AbstractParticleInstance, + particlesAtNode::Array{Array{Array{Any,1},1},1}, S::StateTypeL1, Failed::Vector{AbstractMarkedParticleInstance}, Grid::Union{Grid2D,MeshGrids}, @@ -243,7 +259,8 @@ function advance!(PI::AbstractParticleInstance, #if PI.ODEIntegrator.u[1] > -13.0 #ODEs.log_energy_minimum # the minimum enerçy is distributed to 4 neighbouring particles if PI.on - ParticleToNode!(PI, S, Grid, periodic_boundary) + ParticleToNode!(PI, particlesAtNode, S, Grid, periodic_boundary) + # ParticleToNode!(PI, S, Grid, periodic_boundary) end #return PI diff --git a/src/ParticleInCell.jl b/src/ParticleInCell.jl index bef1e2d..d78e315 100644 --- a/src/ParticleInCell.jl +++ b/src/ParticleInCell.jl @@ -10,7 +10,7 @@ using ..custom_structures: wni, N_Periodic, N_NonPeriodic, N_TripolarNorth # %% using ..ParticleMesh -#using ...Architectures: AbstractParticleInstance +using ...Architectures: AbstractParticleInstance # Tolerance for comparison of real numbers: set it here! # Set parameters @@ -340,28 +340,28 @@ end # ## most recent version 2D - not with Boundary types -# function push_to_grid!(grid::SharedArray{Float64, 3}, -# particlesAtNode::Array{Array{Array{Any,1},1},1}, -# PI::AbstractParticleInstance, -# charge::Vector{Float64}, -# index_pos::Tuple{Int, Int}, -# weights::Tuple{Float64, Float64}, -# Nx::Int, Ny::Int, -# periodic::Bool = true) -# if periodic -# grid[ wrap_index!(index_pos[1], Nx) , wrap_index!(index_pos[2], Ny), : ] += weights[1] * weights[2] * charge -# else -# if sum( test_domain(index_pos, Nx, Ny) ) != 2 -# # position outside of domain -# return -# else -# # position is inside the domain -# push!(particlesAtNode[index_pos[1]][index_pos[2]], [weights[1] * weights[2], charge[4], PI]) -# grid[ index_pos[1] , index_pos[2], 1:3 ] += weights[1] * weights[2] * charge[1:3] -# end -# end +function push_to_grid!(grid::SharedArray{Float64, 3}, + particlesAtNode::Array{Array{Array{Any,1},1},1}, + PI::AbstractParticleInstance, + charge::Vector{Float64}, + index_pos::Tuple{Int, Int}, + weights::Tuple{Float64, Float64}, + Nx::Int, Ny::Int, + periodic::Bool = true) + if periodic + grid[ wrap_index!(index_pos[1], Nx) , wrap_index!(index_pos[2], Ny), : ] += weights[1] * weights[2] * charge + else + if sum( test_domain(index_pos, Nx, Ny) ) != 2 + # position outside of domain + return + else + # position is inside the domain + push!(particlesAtNode[index_pos[1]][index_pos[2]], [weights[1] * weights[2], charge[4], PI]) + grid[ index_pos[1] , index_pos[2], 1:3 ] += weights[1] * weights[2] * charge[1:3] + end + end -# end +end # Abstract Boundary Version function push_to_grid!(grid::StateTypeL1, @@ -514,19 +514,19 @@ function push_to_grid!(grid::StateTypeL1, end end -# function push_to_grid!(grid::SharedArray{Float64, 3}, -# particlesAtNode::Array{Array{Array{Any,1},1},1}, -# PI::AbstractParticleInstance, -# charge::Vector{Float64}, -# index_pos::Vector{Tuple{Int, Int}}, -# weights::Vector{Tuple{Float64, Float64}}, -# Nx::Int, Ny::Int, -# periodic::Bool=true) -# #@info "this is version D" -# for (i, w) in zip(index_pos, weights) -# push_to_grid!(grid, particlesAtNode, PI, charge , i, w , Nx, Ny, periodic) -# end -# end +function push_to_grid!(grid::SharedArray{Float64, 3}, + particlesAtNode::Array{Array{Array{Any,1},1},1}, + PI::AbstractParticleInstance, + charge::Vector{Float64}, + index_pos::Vector{Tuple{Int, Int}}, + weights::Vector{Tuple{Float64, Float64}}, + Nx::Int, Ny::Int, + periodic::Bool=true) + #@info "this is version D" + for (i, w) in zip(index_pos, weights) + push_to_grid!(grid, particlesAtNode, PI, charge , i, w , Nx, Ny, periodic) + end +end #push_to_grid!(charges_grid, 1.0 , index_positions[3], weights[3] , grid2d.Nx , grid2d.Ny ) ## allocation optimized: @@ -551,18 +551,18 @@ end """ wrapper over FieldVector weight&index (wni), """ -# function push_to_grid!(grid::SharedArray{Float64, 3}, -# particlesAtNode::Array{Array{Array{Any,1},1},1}, -# PI::AbstractParticleInstance, -# charge::CC, -# wni::FieldVector, -# Nx::Int, Ny::Int, -# periodic::Bool=true) where CC <: Union{Vector{Float64}, SVector{3, Float64}} -# #@info "this is version D" -# for (i, w) in construct_loop(wni) -# push_to_grid!(grid,particlesAtNode, PI, charge, i, w, Nx, Ny, periodic) -# end -# end +function push_to_grid!(grid::SharedArray{Float64, 3}, + particlesAtNode::Array{Array{Array{Any,1},1},1}, + PI::AbstractParticleInstance, + charge::CC, + wni::FieldVector, + Nx::Int, Ny::Int, + periodic::Bool=true) where CC <: Union{Vector{Float64}, SVector{3, Float64}} + #@info "this is version D" + for (i, w) in construct_loop(wni) + push_to_grid!(grid,particlesAtNode, PI, charge, i, w, Nx, Ny, periodic) + end +end function push_to_grid!(grid::StateTypeL1, charge::CC, diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index 7660bee..4f2fa97 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -1,4 +1,6 @@ -using ..Operators.core_2D_spread: ParticleDefaults, SeedParticle +using ..Operators.core_2D_spread: SeedParticle +using ..Operators.core_2D_spread: ParticleDefaults as ParticleDefaults2D +using ..Operators.core_1D: ParticleDefaults as ParticleDefaults1D using ..Operators.core_1D: SeedParticle! as SeedParticle1D! using ..Operators.core_2D_spread: SeedParticle! as SeedParticle2D! @@ -227,8 +229,8 @@ initialize_simulation!(sim::Simulation) initialize the simulation sim by calling init_particles! to initialize the model.ParticleCollection. -particle_initials::T=nothing was removed from arguments """ -function initialize_simulation!(sim::Simulation)# where {PP<:Union{ParticleDefaults,Nothing}} - # copy(ParticleDefaults(log(4e-8), 1e-2, 0.0))) +function initialize_simulation!(sim::Simulation)# where {PP<:Union{ParticleDefaults2D,Nothing}} + # copy(ParticleDefaults2D(log(4e-8), 1e-2, 0.0))) if sim.verbose @info "init particles..." @@ -251,7 +253,7 @@ reset_simulation!(sim::Simulation) reset the simulation sim by calling init_particles! to reinitialize the model.ParticleCollection, sets the model.clock.time, model.clock.iteration, and model.state to 0. - particle_initials::Dict{Num, Float64} was removed from arguments """ -function reset_simulation!(sim::Simulation)# where {PP<:Union{ParticleDefaults,Nothing}} +function reset_simulation!(sim::Simulation)# where {PP<:Union{ParticleDefaults2D,Nothing}} sim.running = false sim.run_wall_time = 0.0 @@ -296,7 +298,7 @@ initialize the model.ParticleCollection based on the model.grid and the defaults If defaults is nothing, then the model.ODEdev is used. usually the initilization uses wind constitions to seed the particles. """ -function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose::Bool=false) where {PP<:Union{ParticleDefaults1D,ParticleDefaults2D,Nothing}} +function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose::Bool=false) where {PP<:Union{ParticleDefaults1D,ParticleDefaults2D,Array{Any,1},Nothing}} #defaults = isnothing(defaults) ? model.ODEdev : defaults if verbose @info "seed PiCLES ... \n" @@ -317,28 +319,12 @@ function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose:: gridnotes, model.winds, model.ODEsettings.timestep, model.boundary, model.periodic_boundary) - #end, CartesianIndices(model.grid.data) - - # threads for loop version - # ParticleCollection = StructArray{ParticleInstance2D}(undef, grid.stats.Nx, grid.stats.Ny) - - # speed tests - # 1 thread 8.736 ms (124253 allocations: 12.39 MiB) - # 4 thread 4.443 ms (123316 allocations: 12.35 MiB) - # @btime @threads for ij in CartesianIndices(mesh) - # ParticleCollection4[ij] = SeedParticle( - # model.State, ij, - # model.ODEsystem, defaults, model.ODEsettings, - # model.grid.stats, ij_mesh, ij_wind, - # model.DT, - # model.boundary, model.periodic_boundary) - # end @info typeof(ParticleCollection) - # @info ParticleCollection + model.ParticleCollection = ParticleCollection - if defaults isa ParticleDefaults + if defaults isa ParticleDefaults2D i = Int64(floor((defaults.x - model.grid.xmin) / model.grid.dx)) + 1 j = Int64(floor((defaults.y - model.grid.ymin) / model.grid.dy)) + 1 gridnotes = TwoDGridNotes(model.grid) From 811e000b9e5ffc7eab9c65f093422c21e607f4d6 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Fri, 9 Jan 2026 16:22:48 +0100 Subject: [PATCH 32/37] adapted functions in run.jl to the new Abstract2DStochasticModel --- src/Simulations/run.jl | 81 ++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index 4f2fa97..7959bab 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -5,7 +5,7 @@ using ..Operators.core_1D: ParticleDefaults as ParticleDefaults1D using ..Operators.core_1D: SeedParticle! as SeedParticle1D! using ..Operators.core_2D_spread: SeedParticle! as SeedParticle2D! -using ..Architectures: Abstract2DModel, Abstract1DModel +using ..Architectures: Abstract2DModel, Abstract1DModel, Abstract2DStochasticModel using ..ParticleMesh: OneDGrid, OneDGridNotes, TwoDGrid, TwoDGridNotes #using WaveGrowthModels: init_particles! @@ -298,7 +298,7 @@ initialize the model.ParticleCollection based on the model.grid and the defaults If defaults is nothing, then the model.ODEdev is used. usually the initilization uses wind constitions to seed the particles. """ -function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose::Bool=false) where {PP<:Union{ParticleDefaults1D,ParticleDefaults2D,Array{Any,1},Nothing}} +function init_particles!(model::Abstract2DStochasticModel; defaults::PP=nothing, verbose::Bool=false) where {PP<:Union{ParticleDefaults1D,ParticleDefaults2D,Array{Any,1},Nothing}} #defaults = isnothing(defaults) ? model.ODEdev : defaults if verbose @info "seed PiCLES ... \n" @@ -371,35 +371,6 @@ function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose:: model.ODEsettings.timestep, model.boundary, model.periodic_boundary)) end - # for _ in 1:n_part - # temp_boucle = true - # while temp_boucle - # defaults_temp = deepcopy(defaults) - # mu = [defaults_temp.c̄_x, defaults_temp.c̄_y, defaults_temp.x, defaults_temp.y] - # d = MvNormal(mu, model.proba_covariance_init) - # real = rand(d,1) - # delta_phi = real[1] - # #delta_phi < 0 ? delta_phi = - delta_phi : delta_phi = delta_phi - # #delta_phi < 0.01 ? delta_phi+=1 : delta_phi +=0 - # #c_x = (real[2]+1)*(defaults_temp.c̄_x * cos(delta_phi) - defaults_temp.c̄_y * sin(delta_phi)) - # #c_y = (real[2]+1)*(defaults_temp.c̄_x * sin(delta_phi) + defaults_temp.c̄_y * cos(delta_phi)) - # c_x = real[1] - # c_y = real[2] - # defaults_temp.lne += -log(n_part) - # defaults_temp.c̄_x = c_x - # defaults_temp.c̄_y = c_y - # defaults_temp.x = real[3] - # defaults_temp.y = real[4] - # if c_x^2+c_y^2<=1 - # push!(ParticleCollection, SeedParticle(model.State, - # (i,j), model.ODEsystem, defaults_temp, - # model.ODEsettings,gridnotes, model.winds, - # model.ODEsettings.timestep, model.boundary, - # model.periodic_boundary)) - # temp_boucle = false - # end - # end - # end end else push!(ParticleCollection, SeedParticle(model.State, @@ -423,7 +394,55 @@ function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose:: nothing end +function init_particles!(model::Abstract2DModel; defaults::PP=nothing, verbose::Bool=false) where {PP<:Union{ParticleDefaults1D,ParticleDefaults2D,Nothing}} + #defaults = isnothing(defaults) ? model.ODEdev : defaults + if verbose + @info "seed PiCLES ... \n" + @info "defaults is $(defaults)" + if defaults isa Dict + @info "found particle initials, just replace position " + else + @info "no particle defaults found, use windsea to seed particles" + end + end + ParticleCollection = StructArray(map(ij -> begin + + ij_mesh = model.grid.data[ij] + ij_wind = ( model.winds.u(ij_mesh.x, ij_mesh.y, 0.0), + model.winds.v(ij_mesh.x, ij_mesh.y, 0.0) + ) + + SeedParticle2D( + model.State, ij, + model.ODEsystem, defaults, model.ODEsettings, + model.grid.stats, model.grid.ProjetionKernel, model.grid.PropagationCorrection, + ij_mesh, ij_wind, + model.ODEsettings.timestep, + model.boundary, model.periodic_boundary) + + end, CartesianIndices(model.grid.data))) + + + # threads for loop version + # ParticleCollection = StructArray{ParticleInstance2D}(undef, grid.stats.Nx, grid.stats.Ny) + + # speed tests + # 1 thread 8.736 ms (124253 allocations: 12.39 MiB) + # 4 thread 4.443 ms (123316 allocations: 12.35 MiB) + # @btime @threads for ij in CartesianIndices(mesh) + # ParticleCollection4[ij] = SeedParticle( + # model.State, ij, + # model.ODEsystem, defaults, model.ODEsettings, + # model.grid.stats, ij_mesh, ij_wind, + # model.DT, + # model.boundary, model.periodic_boundary) + # end + @info typeof(ParticleCollection) + # @info ParticleCollection + model.ParticleCollection = ParticleCollection + nothing +end From 5d18f6bb491f9ec478887e88b485aba4e42a948f Mon Sep 17 00:00:00 2001 From: tomprotin Date: Fri, 9 Jan 2026 16:43:02 +0100 Subject: [PATCH 33/37] adapted functions in mapping_2D.jl to the new Abstract2DStochasticModel --- src/Operators/mapping_2D.jl | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index 36758aa..8a41ee8 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -95,7 +95,7 @@ function ParticleToNode!(PI::AbstractParticleInstance, S::SharedMatrix, u_state: nothing end -function set_u_and_t!(integrator, u_new::CC, t_new::Number) where CC <:Union{Vector{Float64},MVector} +function set_u_and_t_stochas!(integrator, u_new::CC, t_new::Number) where CC <:Union{Vector{Float64},MVector} # adding a small deviation due to directional spreading d = Normal(0, u_new[6]^2) delta_phi = rand(d,1) @@ -107,6 +107,11 @@ function set_u_and_t!(integrator, u_new::CC, t_new::Number) where CC <:Union{Vec integrator.t = t_new end +function set_u_and_t!(integrator, u_new::CC, t_new::Number) where CC <:Union{Vector{Float64},MVector} + integrator.u = u_new + integrator.t = t_new +end + function reset_PI_u!(PI::AbstractParticleInstance; ui::CC) where CC<:Union{Vector{Float64},MVector{Float64}} # this method keeps the correct time for time varying forcing (~may 2023) @@ -116,9 +121,15 @@ function reset_PI_u!(PI::AbstractParticleInstance; ui::CC) where CC<:Union{Vecto end -function reset_PI_ut!(PI::AbstractParticleInstance; ui::CC, ti::Number) where CC <:Union{Vector{Float64},MVector} +function reset_PI_ut!(PI::AbstractParticleInstance; ui::CC, ti::Number, stochas::Bool) where CC <:Union{Vector{Float64},MVector} # this method keeps the correct time for time varying forcing (~may 2023) - set_u_and_t!(PI.ODEIntegrator, ui, ti) + if stochas + set_u_and_t_stochas!(PI.ODEIntegrator, ui, ti) + @info "called the correct version" + else + @info "called the wrong version" + set_u_and_t!(PI.ODEIntegrator, ui, ti) + end u_modified!(PI.ODEIntegrator, true) auto_dt_reset!(PI.ODEIntegrator) end @@ -415,7 +426,7 @@ end Wrapper function that does everything necessary to remesh the particles. - pushes the Node State to particle instance """ -function remesh!(i::Int64, j::Int64, model::Abstract2DModel, DT::Float64) +function remesh!(i::Int64, j::Int64, model::Abstract2DStochasticModel, DT::Float64) winds = model.winds ti = model.clock.time grid = model.grid @@ -466,7 +477,7 @@ function NodeToParticle!(PI::AbstractParticleInstance, S::StateTypeL1, #@show "u_state", u_state ui = GetVariablesAtVertex(u_state, xy[1], xy[2]) #@info exp(ui[1]), ui[2], ui[4]/1e3, ui[5]/1e3 - reset_PI_ut!(PI; ui=ui, ti=last_t) + reset_PI_ut!(PI; ui=ui, ti=last_t, stochas=true) PI.on = true # this method is more robust than the set_u! method (~february 2023) From 09ff80f2d3d99e7e79492f2306d11b5b35abb161 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Fri, 16 Jan 2026 17:10:07 +0100 Subject: [PATCH 34/37] changed the stochastic method so it uses new grid system, new particle type, and new model type --- src/Architectures.jl | 3 +- src/Models/GeometricalOpticsModels.jl | 63 ++------ src/Models/Models.jl | 6 +- src/Models/WaveGrowthModels2D.jl | 6 +- src/Operators/TimeSteppers.jl | 11 +- src/Operators/core_2D_spread.jl | 178 +++++++++++++++-------- src/Operators/initialize.jl | 2 +- src/Operators/mapping_2D.jl | 15 +- src/ParticleInCell.jl | 21 +-- src/ParticleSystems/particle_waves_v5.jl | 2 +- src/ParticleSystems/particle_waves_v6.jl | 2 +- src/PiCLES.jl | 6 +- src/Simulations/run.jl | 78 +++++----- src/custom_structures.jl | 12 +- tests/test_case_1.jl | 7 +- 15 files changed, 229 insertions(+), 183 deletions(-) diff --git a/src/Architectures.jl b/src/Architectures.jl index b60426a..b177856 100644 --- a/src/Architectures.jl +++ b/src/Architectures.jl @@ -4,7 +4,7 @@ using SharedArrays using StaticArrays -export AbstractGrid, AbstractODESettings, AbstractParticleInstance, AbstractMarkedParticleInstance, Abstract1DModel, Abstract2DModel, Abstract2DStochasticModel, AbstractModel, AbstractStore, AbstractParticleSystem, StateTypeL1, IDConstantsInstance, ScgConstantsInstance, CartesianGrid, CartesianGrid1D, CartesianGrid2D, TripolarGrid, Grid2D, MeshGrids, MeshGridStatistics +export AbstractGrid, AbstractODESettings, AbstractParticleInstance, AbstractMarkedParticleInstance, Abstract1DModel, Abstract2DModel, Abstract2DStochasticModel, AbstractModel, AbstractStore, AbstractParticleSystem, StateTypeL1, IDConstantsInstance, ScgConstantsInstance, CartesianGrid, CartesianGrid1D, CartesianGrid2D, TripolarGrid, Grid2D, MeshGrids, MeshGridStatistics, AbstractStochasticParticleInstance export StandardRegular1D_old, StandardRegular2D_old @@ -39,6 +39,7 @@ MeshGridStatistics = Union{CartesianGridStatistics,TripolarGridStatistics,Spheri abstract type AbstractODESettings end abstract type AbstractParticleInstance end +abstract type AbstractStochasticParticleInstance <: AbstractParticleInstance end abstract type AbstractMarkedParticleInstance end abstract type IDConstantsInstance end diff --git a/src/Models/GeometricalOpticsModels.jl b/src/Models/GeometricalOpticsModels.jl index 13b1c35..1cd791f 100644 --- a/src/Models/GeometricalOpticsModels.jl +++ b/src/Models/GeometricalOpticsModels.jl @@ -24,7 +24,8 @@ using ...FetchRelations using LinearAlgebra -#includet("mapping_1D.jl") +using ..WaveGrowthModels2D +# include("WaveGrowthModels2D.jl") # TO DO : check if all the modules imported above are necessary, for now I just copied the ones from WaveGrowthModels2D.jl @@ -111,21 +112,6 @@ end ## 2D version -""" -mark_boundary(grid::TwoDGrid) -function that returns list of boundary nodes (tuples of indixes) -""" -function mark_boundary(grid::TwoDGrid) - #get x and y coordinates - xi = collect(range(1, stop=grid.Nx, step=1)) - yi = collect(range(1, stop=grid.Ny, step=1)) - - # make boundary nodes - a = [(xi[i], yi[j]) for j in 1:grid.Ny , i in [1, grid.Nx]] - b = [(xi[i], yi[j]) for j in [1, grid.Ny], i in 1:grid.Nx ] - #merge a and b - return vcat(vec(a), vec(b)) #vec(vcat(a, b)) -end """ @@ -143,7 +129,7 @@ GeometricalOptics(; grid, winds, ODEsys, ODEvars, layers, clock, ODEsets, ODEdef periodic_boundary: if true we use a periodic boundary (default true), CBsets : the callback settings (not implimented yet). """ -function GeometricalOptics(; grid::TwoDGrid, +function GeometricalOptics(; grid::GG, winds::NamedTuple{(:u, :v)}, ODEsys, ODEvars=nothing, #needed for MTK for ODEsystem. will be depriciated later @@ -164,22 +150,23 @@ function GeometricalOptics(; grid::TwoDGrid, save_particles=false, n_particles_launch=150, CBsets=nothing, - movie=false) where {PP<:Union{ParticleDefaults2D,String}} + movie=false) where {PP<:Union{ParticleDefaults2D,String},GG<:AbstractGrid} # initialize state {SharedArray} given grid and layers # Number of state variables Nstate = 4 - if layers > 1 - State = SharedArray{Float64,4}(grid.Nx, grid.Ny, Nstate, layers) - else - State = SharedArray{Float64,3}(grid.Nx, grid.Ny, Nstate) - end + State = init_StateArray(grid, Nstate, layers) + # if layers > 1 + # State = SharedArray{Float64,4}(grid.stats.Nx.N, grid.stats.Ny.N, Nstate, layers) + # else + # State = SharedArray{Float64,3}(grid.stats.Nx.N, grid.stats.Ny.N, Nstate) + # end if layers > 1 ParticlesAtNode = Array{Array{Array{Array{Any,1},1},1},1}() - for i in 1:grid.Nx + for i in 1:grid.stats.Nx.N push!(ParticlesAtNode, []) - for j in 1:grid.Ny + for j in 1:grid.stats.Ny.N push!(ParticlesAtNode[i], []) for _ in 1:layers push!(ParticlesAtNode[i][j], []) @@ -189,9 +176,9 @@ function GeometricalOptics(; grid::TwoDGrid, ParticlePool = Array{Array{Any,1},1}() else ParticlesAtNode = Array{Array{Array{Any,1},1},1}() - for i in 1:grid.Nx + for i in 1:grid.stats.Nx.N push!(ParticlesAtNode, []) - for _ in 1:grid.Ny + for _ in 1:grid.stats.Ny.N push!(ParticlesAtNode[i], []) end end @@ -203,7 +190,7 @@ function GeometricalOptics(; grid::TwoDGrid, elseif ODEinit_type == "wind_sea" ODEdefaults = nothing elseif ODEinit_type == "mininmal" - ODEdefaults = ParticleDefaults1D(-11.0, 1e-3, 0.0) + ODEdefaults = ParticleDefaults2D(-11.0, 1e-3, 0.0) else error("ODEinit_type must be either 'wind_sea','mininmal', or ParticleDefaults2D instance ") end @@ -302,26 +289,6 @@ end -""" - fields(model::WaveGrowth) - -Return a flattened `NamedTuple` of the State vector for a `GeometricalOptics` model. -""" -fields(model::GeometricalOptics) = (State=model.State,) -# # Oceananigans.Simulations interface -# fields(m::ContinuumIceModel) = merge(m.velocities, m.stresses) - -function reset_boundary!(model::GeometricalOptics) - - if model.periodic_boundary # if false, define boundary points here: - boundary = [] - else - boundary = boundary = mark_boundary(grid) - end - -end - - function Base.show(io::IO, ow::GeometricalOptics) if ow.ODEsystem isa ODESystem diff --git a/src/Models/Models.jl b/src/Models/Models.jl index 7459798..b77c47a 100644 --- a/src/Models/Models.jl +++ b/src/Models/Models.jl @@ -3,11 +3,11 @@ module Models export WaveGrowthModels1D, WaveGrowthModels2D, GeometricalOpticsModels, reset_boundary! include("WaveGrowthModels1D.jl") -include("WaveGrowthModels2D.jl") -include("GeometricalOpticsModels.jl") - using .WaveGrowthModels1D +include("WaveGrowthModels2D.jl") using .WaveGrowthModels2D +include("GeometricalOpticsModels.jl") using .GeometricalOpticsModels + end \ No newline at end of file diff --git a/src/Models/WaveGrowthModels2D.jl b/src/Models/WaveGrowthModels2D.jl index bc06fc0..b1dd20f 100644 --- a/src/Models/WaveGrowthModels2D.jl +++ b/src/Models/WaveGrowthModels2D.jl @@ -1,6 +1,6 @@ module WaveGrowthModels2D -export WaveGrowth2D, init_particles! +export WaveGrowth2D, init_particles!, init_StateArray, mark_boundary, reset_boundary!, fields export fields using ...Architectures @@ -352,11 +352,11 @@ end Return a flattened `NamedTuple` of the State vector for a `WaveGrowth2D` model. """ -fields(model::WaveGrowth2D) = (State=model.State,) +fields(model::Abstract2DModel) = (State=model.State,) # # Oceananigans.Simulations interface # fields(m::ContinuumIceModel) = merge(m.velocities, m.stresses) -function reset_boundary!(model::WaveGrowth2D) +function reset_boundary!(model::Abstract2DModel) if model.periodic_boundary # if false, define boundary points here: boundary = [] diff --git a/src/Operators/TimeSteppers.jl b/src/Operators/TimeSteppers.jl index 5f2ca8e..84eae36 100644 --- a/src/Operators/TimeSteppers.jl +++ b/src/Operators/TimeSteppers.jl @@ -151,8 +151,7 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb @info maximum(model.State[:, :, 1]), maximum(model.State[:, :, 2]), maximum(model.State[:, :, 3]) model.FailedCollection = FailedCollection end - - for (i,j) in [(i,j) for i in 1:model.grid.Nx for j in 1:model.grid.Ny] + for (i,j) in [(i,j) for i in 1:model.grid.stats.Nx.N for j in 1:model.grid.stats.Ny.N] for k in 1:length(model.ParticlesAtNode[i][j]) pop!(model.ParticlesAtNode[i][j]) end @@ -172,7 +171,7 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb write_particles_to_csv(model, Δt) end - for (i,j) in [(i,j) for i in 1:model.grid.Nx for j in 1:model.grid.Ny] + for (i,j) in [(i,j) for i in 1:model.grid.stats.Nx.N for j in 1:model.grid.stats.Ny.N] weights = [model.ParticlesAtNode[i][j][k][1] for k in 1:length(model.ParticlesAtNode[i][j])] values = [model.ParticlesAtNode[i][j][k][2] for k in 1:length(model.ParticlesAtNode[i][j])] if length(weights) > 0 @@ -233,7 +232,7 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb nPreviousParticles = 0 model.ParticlePool = [] - @threads for (i,j) in [(i,j) for i in 1:model.grid.Nx for j in 1:model.grid.Ny] + @threads for (i,j) in [(i,j) for i in 1:model.grid.stats.Nx.N for j in 1:model.grid.stats.Ny.N] locallen = length(model.ParticlesAtNode[i][j]) nPreviousParticles += locallen @threads for k in 1:locallen @@ -288,8 +287,8 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb for k in 1:nNewParticles i = model.ParticlePool[particlesDrawn[k]][2] j = model.ParticlePool[particlesDrawn[k]][3] - x = model.grid.xmin + model.grid.dx*(i-1) - y = model.grid.ymin + model.grid.dy*(j-1) + x = model.grid.stats.xmin + model.grid.stats.dx*(i-1) + y = model.grid.stats.ymin + model.grid.stats.dy*(j-1) #log_energy = log(totEnergyDomain[1]/nPreviousParticles) log_energy = log(ParticuleEnergiesNorm/nNewParticles) c_x = model.ParticlePool[particlesDrawn[k]][1].ODEIntegrator.u[2] diff --git a/src/Operators/core_2D_spread.jl b/src/Operators/core_2D_spread.jl index 0b028fb..84120fc 100644 --- a/src/Operators/core_2D_spread.jl +++ b/src/Operators/core_2D_spread.jl @@ -14,12 +14,12 @@ export InitParticleValues using ...FetchRelations using ...Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, StateTypeL1 - +using ...Architectures: AbstractGridStatistics # using ..particle_waves_v3: init_vars # t, x, y, c̄_x, c̄_y, lne, Δn, Δφ_p, r_g, C_α, C_φ, g, C_e = init_vars() -using ...custom_structures: ParticleInstance1D, ParticleInstance2D, MarkedParticleInstance +using ...custom_structures: ParticleInstance1D, StochasticParticleInstance2D, MarkedParticleInstance export init_z0_to_State! include("initialize.jl") @@ -190,7 +190,7 @@ function InitParticleInstance(model, z_initials, ODE_settings, ij, boundary_flag reltol=ODE_settings.reltol, callback=ODE_settings.callbacks, save_everystep=ODE_settings.save_everystep) - return ParticleInstance2D(ij, (z_initials[4], z_initials[5]), integrator, boundary_flag, particle_on) + return StochasticParticleInstance2D(ij, (z_initials[4], z_initials[5]), integrator, boundary_flag, particle_on) end """ @@ -225,7 +225,7 @@ function InitParticleInstance(model::ODESystem, z_initials, ODE_settings, ij, bo reltol=ODE_settings.reltol, callback=ODE_settings.callbacks, save_everystep=ODE_settings.save_everystep) - return ParticleInstance2D(ij, (z_initials[4], z_initials[5]), integrator, boundary_flag, particle_on) + return StochasticParticleInstance2D(ij, (z_initials[4], z_initials[5]), integrator, boundary_flag, particle_on) end @@ -287,6 +287,52 @@ function InitParticleValues( return particle_defaults, particle_on end +""" +InitParticleInstance(model::WaveGrowth1D, z_initials, pars, ij, boundary_flag, particle_on ; cbSets=nothing) +wrapper function to initalize a particle instance + inputs: + model is an initlized ODESytem + z_initials is the initial state of the ODESystem + pars are the parameters of the ODESystem + ij is the (i,j) tuple that of the particle position + xy is the (x,y) tuple that of the particle position + boundary_flag is a boolean that indicates if the particle is on the boundary + particle_on is a boolean that indicates if the particle is on + chSet (optional) is the set of callbacks the ODE can have +""" +function InitParticleInstance(model, z_initials, ODE_settings, ij, xy , boundary_flag, particle_on; cbSets=Nothing) + + ## to do's for add the Projection: + ## replace boundary_flag with mask that discrimiated by types [0,1,2,3] + ## add M as input to the function and add it to the ODE_parameters + ## modify ParticleInstance2D to deal with boundaries and mask + + # converty to ordered named tuple + ODE_parameters = NamedTuple{Tuple(Symbol.(keys(ODE_settings.Parameters)))}(values(ODE_settings.Parameters)) + ODE_parameters = (; ODE_parameters..., x = xy[1], y = xy[2]) + + z_initials = initParticleDefaults(z_initials) + # create ODEProblem + problem = ODEProblem(model, z_initials, (0.0, ODE_settings.total_time), ODE_parameters) + # inialize problem + # works best with abstol = 1e-4,reltol=1e-3,maxiters=1e4, + integrator = init( + problem, + ODE_settings.solver, + saveat=ODE_settings.saving_step, + abstol=ODE_settings.abstol, + adaptive=ODE_settings.adaptive, + dt = ODE_settings.dt, + dtmin=ODE_settings.dtmin, + force_dtmin=ODE_settings.force_dtmin, + maxiters=ODE_settings.maxiters, + reltol=ODE_settings.reltol, + callback=ODE_settings.callbacks, + save_everystep=ODE_settings.save_everystep) + + return StochasticParticleInstance2D(ij, (xy[1], xy[2]), integrator, boundary_flag, particle_on) +end + # --------------------------- up to here for now (remove MTK)--------------------------- # @@ -346,7 +392,13 @@ function check_boundary_point(i, boundary, periodic_boundary) return periodic_boundary ? false : (i in boundary) end - +function check_boundary_point(imesh, periodic_boundary) + if periodic_boundary + return imesh == 2 # only land points are treated as boundary points + else + return imesh >= 2 # land points and grid boundary points are treated as boundary points + end +end # """ @@ -409,91 +461,99 @@ end """ -SeedParticle(State::SharedMatrix, i::Int64, - particle_system::ODESystem, particle_defaults::Union{ParticleDefaults,Nothing}, ODE_settings, - GridNotes, winds, DT:: Float64, Nx:: Int, boundary::Vector{Int}, periodic_boundary::Bool) + function SeedParticle(State::StateTypeL1, ij:: (Int64, Int64) + particle_system::Any, particle_defaults::Union{ParticleDefaults,Nothing}, ODE_settings, + ij_mesh, ij_wind_tuple, DT:: Float64, boundary::Vector{Int}, periodic_boundary::Bool) -return ParicleInstance that can be pushed to ParticleColletion + returns ParicleInstance that can be pushed to ParticleColletion """ function SeedParticle( - State::SharedArray, - ij::Tuple{Int, Int}, - + State::StateTypeL1, + ij::II, # position tuple in grid + particle_system::SS, particle_defaults::PP, ODE_settings, #particle_waves_v3.ODESettings type + + gridstats::AbstractGridStatistics, + ProjetionKernel::Function, + PropagationCorrection::Function, - GridNotes, # ad type of grid note - winds, # interp winds - DT::Float64, - - boundary::Vector{T}, - periodic_boundary::Bool) where {T<:Union{Int,Any,Nothing,Int64},PP<:Union{ParticleDefaults,Nothing},SS<:Union{ODESystem,Any}} - - xx, yy = GridNotes.x[ij[1]], GridNotes.y[ij[2]] + ij_mesh::NamedTuple, # local grid information + ij_wind::Tuple, # interp winds - #uv = winds.u(xx, yy, 0)::Union{Num,Float64}, winds.v(xx, yy, 0)::Union{Num,Float64} - uv = winds.u(xx, yy, 0.0)::Float64, winds.v(xx, yy, 0.0)::Float64 + DT::Float64, + boundary::Vector{T}, periodic_boundary::Bool) where + {II<:Union{Tuple{Int,Int},CartesianIndex},T<:Union{Int,Any,Nothing,Int64},PP<:Union{ParticleDefaults,Nothing},SS<:Any} + + xy = (ij_mesh.x, ij_mesh.y) + # 1st check if particle is not in mask, Land points == 0 + if ij_mesh.mask == 0 # land point + # init dummy instance + return StochasticParticleInstance2D(ij, xy , nothing, false, false) + end # define initial condition - z_i, particle_on = InitParticleValues(particle_defaults, (xx,yy), uv, DT) - # check if point is boundary point - boundary_point = check_boundary_point(ij, boundary, periodic_boundary) - #@info "boundary?", boundary_point + # particle initial condition is always (0,0) in relative coordinates not xy anymore + z_i, particle_on = InitParticleValues(particle_defaults, (0.0, 0.0) , ij_wind, DT) - # if boundary_point - # #@info "boundary point", boundary_point, particle_on - # # if boundary point, then set particle to off - # particle_on = false - # end + # check if point is boundary point <-- replace in the future with with mask: 0 = land, 1 = ocean, 2= land boundary, 3 = domain boundary + # boundary_point = check_boundary_point(ij, boundary, periodic_boundary) # old version that compares to list + boundary_point = check_boundary_point(ij_mesh.mask, periodic_boundary) # add initial state to State vector if particle_on init_z0_to_State!(State, ij, GetParticleEnergyMomentum(z_i)) end + # check if Propgation Correction is set in gridstats + # PropagationCorrection = gridstats.PropagationCorrection != nothing ? PropagationCorrection(ij_mesh, gridstats) : x -> 0.0 + + # set projection: + ODE_settings.Parameters = (; ODE_settings.Parameters..., M=ProjetionKernel(ij_mesh, gridstats), PC=PropagationCorrection(ij_mesh, gridstats)) + return InitParticleInstance( particle_system, z_i, ODE_settings, ij, + xy, boundary_point, particle_on) - end - +end -""" -SeedParticle!(ParticleCollection ::Vector{Any}, State::SharedMatrix, i::Int64, - particle_system::ODESystem, particle_defaults::Union{ParticleDefaults,Nothing}, ODE_settings, - GridNotes, winds, DT:: Float64, Nx:: Int, boundary::Vector{Int}, periodic_boundary::Bool) +# """ +# SeedParticle!(ParticleCollection ::Vector{Any}, State::SharedMatrix, i::Int64, +# particle_system::ODESystem, particle_defaults::Union{ParticleDefaults,Nothing}, ODE_settings, +# GridNotes, winds, DT:: Float64, Nx:: Int, boundary::Vector{Int}, periodic_boundary::Bool) -Seed Pickles to ParticleColletion and State -""" -function SeedParticle!( - ParticleCollection::Vector{Any}, - State::SharedArray, - ij::Tuple{Int, Int}, +# Seed Pickles to ParticleColletion and State +# """ +# function SeedParticle!( +# ParticleCollection::Vector{Any}, +# State::SharedArray, +# ij::Tuple{Int, Int}, - particle_system::SS, - particle_defaults::PP, - ODE_settings, #particle_waves_v3.ODESettings type +# particle_system::SS, +# particle_defaults::PP, +# ODE_settings, #particle_waves_v3.ODESettings type - GridNotes, # ad type of grid note - winds, # interp winds - DT::Float64, +# GridNotes, # ad type of grid note +# winds, # interp winds +# DT::Float64, - boundary::Vector{T}, - periodic_boundary::Bool) where {T<:Union{Int,Any,Nothing,Int64},PP<:Union{ParticleDefaults,Nothing},SS<:Union{ODESystem,Any}} +# boundary::Vector{T}, +# periodic_boundary::Bool) where {T<:Union{Int,Any,Nothing,Int64},PP<:Union{ParticleDefaults,Nothing},SS<:Union{ODESystem,Any}} - # Push Inital condition to collection - push!(ParticleCollection, - SeedParticle(State, ij, - particle_system, particle_defaults, ODE_settings, #particle_waves_v3.ODESettings type - GridNotes, winds, DT, - boundary, periodic_boundary)) - nothing -end +# # Push Inital condition to collection +# push!(ParticleCollection, +# SeedParticle(State, ij, +# particle_system, particle_defaults, ODE_settings, #particle_waves_v3.ODESettings type +# GridNotes, winds, DT, +# boundary, periodic_boundary)) +# nothing +# end diff --git a/src/Operators/initialize.jl b/src/Operators/initialize.jl index 4c48ff8..d54a2af 100644 --- a/src/Operators/initialize.jl +++ b/src/Operators/initialize.jl @@ -18,7 +18,7 @@ end """ sets particle state values to S. position is taking from particle """ -function set_u_to_shared!(S::StateTypeL1, PI::ParticleInstance2D) +function set_u_to_shared!(S::StateTypeL1, PI::AbstractParticleInstance) S[ PI.position_ij[1], PI.position_ij[2] , :] = PI.ODEIntegrator.u nothing end diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index 8a41ee8..ce0bb5f 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -7,6 +7,7 @@ using Printf using Random, Distributions using ...ParticleMesh: TwoDGrid, TwoDGridNotes +using PiCLES.Grids.CartesianGrid: TwoDCartesianGridMesh, ProjetionKernel, TwoDCartesianGridStatistics import ...ParticleInCell as PIC using ...FetchRelations @@ -38,7 +39,7 @@ S Shared array where particles are stored G (TwoDGrid) Grid that defines the nodepositions """ -function ParticleToNode!(PI::AbstractParticleInstance, particlesAtNode::Array{Array{Array{Any,1},1},1}, S::SharedArray, G::TwoDGrid, periodic_boundary::Bool) +function ParticleToNode!(PI::AbstractParticleInstance, particlesAtNode::Array{Array{Array{Any,1},1},1}, S::SharedArray, G::TwoDCartesianGridMesh, periodic_boundary::Bool) #u[4], u[5] are the x and y positions of the particle #index_positions, weights = PIC.compute_weights_and_index(G, PI.ODEIntegrator.u[4], PI.ODEIntegrator.u[5]) @@ -48,8 +49,8 @@ function ParticleToNode!(PI::AbstractParticleInstance, particlesAtNode::Array{Ar u_state = GetParticleEnergyMomentum(PI.ODEIntegrator.u) #@show u_state - #PIC.push_to_grid!(S, particlesAtNode, PI, u_state , index_positions, weights, G.Nx, G.Ny , periodic_boundary) - PIC.push_to_grid!(S, particlesAtNode, PI, u_state , weights_and_index, G.Nx, G.Ny , periodic_boundary) + #PIC.push_to_grid!(S, particlesAtNode, PI, u_state , index_positions, weights, G.stats.Nx.N, G.stats.Ny.N , periodic_boundary) + PIC.push_to_grid!(S, particlesAtNode, PI, u_state , weights_and_index, G.stats.Nx.N, G.stats.Ny.N , periodic_boundary) nothing end @@ -64,8 +65,8 @@ function ParticleToNode!(PI::AbstractParticleInstance, S::StateTypeL1, G::TwoDGr u_state = GetParticleEnergyMomentum(PI.ODEIntegrator.u) #@show u_state - #PIC.push_to_grid!(S, u_state , index_positions, weights, G.Nx, G.Ny , periodic_boundary) - PIC.push_to_grid!(S, u_state , weights_and_index, G.Nx, G.Ny , periodic_boundary) + #PIC.push_to_grid!(S, u_state , index_positions, weights, G.stats.Nx.N, G.stats.Ny.N , periodic_boundary) + PIC.push_to_grid!(S, u_state , weights_and_index, G.stats.Nx.N, G.stats.Ny.N , periodic_boundary) nothing end @@ -80,7 +81,7 @@ function ParticleToNode!(PI::AbstractParticleInstance, S::StateTypeL1, G::MeshGr u_state = GetParticleEnergyMomentum(PI.ODEIntegrator.u) #@show u_state - #PIC.push_to_grid!(S, u_state , index_positions, weights, G.Nx, G.Ny , periodic_boundary) + #PIC.push_to_grid!(S, u_state , index_positions, weights, G.stats.Nx.N, G.stats.Ny.N , periodic_boundary) PIC.push_to_grid!(S, u_state, weights_and_index, G.stats.Nx, G.stats.Ny) nothing end @@ -334,7 +335,7 @@ function NodeToParticle!(i::Int64, j::Int64, x::Float64, y::Float64, model::Abst wind_min_squared = model.ODEsettings.wind_min_squared default_particle = model.ODEdefaults e_min_log = model.ODEsettings.log_energy_minimum - current_is_boundary = i==0 || i==model.grid.Nx || j==0 || j==model.grid.Ny + current_is_boundary = i==0 || i==model.grid.stats.Nx || j==0 || j==model.grid.Ny # definition of a norm 2 norm(vec) = sqrt(sum([vec[i]^2 for i in eachindex(vec)])) diff --git a/src/ParticleInCell.jl b/src/ParticleInCell.jl index d78e315..16bc854 100644 --- a/src/ParticleInCell.jl +++ b/src/ParticleInCell.jl @@ -2,6 +2,7 @@ module ParticleInCell using ..Architectures: StateTypeL1, AbstractBoundary using Statistics +using ..Grids.CartesianGrid: TwoDCartesianGridMesh, ProjetionKernel, TwoDCartesianGridStatistics using SharedArrays using StaticArrays @@ -100,16 +101,16 @@ end """ -compute_weights_and_index(g_pars::TwoDGrid, xp::Float64, yp:: Float64 ) +compute_weights_and_index(g_pars::TwoDCartesianGridMesh, xp::Float64, yp:: Float64 ) returns indexes and weights for in 2D for single x,y point """ -function compute_weights_and_index(g_pars::TwoDGrid, xp::Float64, yp:: Float64 ) +function compute_weights_and_index(g_pars::TwoDCartesianGridMesh, xp::Float64, yp:: Float64 ) """ 2d wrapper for 1d function """ - xp_normed = norm_distance(xp, g_pars.xmin, g_pars.dx) - yp_normed = norm_distance(yp, g_pars.ymin, g_pars.dy) + xp_normed = norm_distance(xp, g_pars.stats.xmin, g_pars.stats.dx) + yp_normed = norm_distance(yp, g_pars.stats.ymin, g_pars.stats.dy) xi, xw = get_absolute_i_and_w(xp_normed) yi, yw = get_absolute_i_and_w(yp_normed) @@ -122,16 +123,16 @@ end """ -compute_weights_and_index_mininal(g_pars::TwoDGrid, xp::Float64, yp:: Float64 ) +compute_weights_and_index_mininal(g_pars::TwoDCartesianGridMesh, xp::Float64, yp:: Float64 ) returns indexes and weights as FieldVector for in 2D for single x,y point """ -function compute_weights_and_index_mininal(g_pars::TwoDGrid, xp::Float64, yp::Float64) +function compute_weights_and_index_mininal(g_pars::TwoDCartesianGridMesh, xp::Float64, yp::Float64) """ 2d wrapper for 1d function """ - xp_normed = norm_distance(xp, g_pars.xmin, g_pars.dx) # multiples of grid spacing - yp_normed = norm_distance(yp, g_pars.ymin, g_pars.dy) # multiples of grid spacing + xp_normed = norm_distance(xp, g_pars.stats.xmin, g_pars.stats.dx) # multiples of grid spacing + yp_normed = norm_distance(yp, g_pars.stats.ymin, g_pars.stats.dy) # multiples of grid spacing xi, xw = get_absolute_i_and_w(xp_normed) yi, yw = get_absolute_i_and_w(yp_normed) @@ -175,10 +176,10 @@ end #indexes, weights = compute_weights_and_index(grid2d, 10.0, 9.9 ) """ -compute_weights_and_index(g_pars::TwoDGrid, xp::Float64, yp:: Float64 ) +compute_weights_and_index(g_pars::TwoDCartesianGridMesh, xp::Float64, yp:: Float64 ) returns indexes and weights for in 2D for vectors """ -function compute_weights_and_index(grid::TwoDGrid, xp::Vector{Float64}, yp:: Vector{Float64} ) +function compute_weights_and_index(grid::TwoDCartesianGridMesh, xp::Vector{Float64}, yp:: Vector{Float64} ) """ returns: weight list 2 N X 1 vector of tuples with indices and weights diff --git a/src/ParticleSystems/particle_waves_v5.jl b/src/ParticleSystems/particle_waves_v5.jl index 4c3225f..2110003 100644 --- a/src/ParticleSystems/particle_waves_v5.jl +++ b/src/ParticleSystems/particle_waves_v5.jl @@ -4,7 +4,7 @@ using DifferentialEquations, IfElse using ...Architectures: AbstractODESettings, AbstractParticleSystem, IDConstantsInstance, ScgConstantsInstance -export particle_equations, ODESettings +export particle_equations, ODESettings, ODEParameters using LinearAlgebra using StaticArrays diff --git a/src/ParticleSystems/particle_waves_v6.jl b/src/ParticleSystems/particle_waves_v6.jl index a2878f0..d2d7339 100644 --- a/src/ParticleSystems/particle_waves_v6.jl +++ b/src/ParticleSystems/particle_waves_v6.jl @@ -31,7 +31,7 @@ Structure to hold all information about the ODE system # Fields $(DocStringExtensions.FIELDS) """ -@with_kw struct ODESettings <: AbstractODESettings +@with_kw mutable struct ODESettings <: AbstractODESettings "ODE parameters (Dict)" Parameters::NamedTuple "minimum allowed log energy on particle " diff --git a/src/PiCLES.jl b/src/PiCLES.jl index da53c93..8069985 100644 --- a/src/PiCLES.jl +++ b/src/PiCLES.jl @@ -43,14 +43,14 @@ using .ParticleSystems include("FetchRelations.jl") using .FetchRelations +include("Grids/Grids.jl") +using .Grids + include("ParticleMesh.jl") include("ParticleInCell.jl") using .ParticleMesh using .ParticleInCell -include("Grids/Grids.jl") -using .Grids - include("Operators/Operators.jl") include("Simulations/Simulations.jl") diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index 7959bab..cc8fc9c 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -1,9 +1,10 @@ -using ..Operators.core_2D_spread: SeedParticle +using ..Operators.core_2D_spread: SeedParticle as SeedParticle2D using ..Operators.core_2D_spread: ParticleDefaults as ParticleDefaults2D using ..Operators.core_1D: ParticleDefaults as ParticleDefaults1D using ..Operators.core_1D: SeedParticle! as SeedParticle1D! using ..Operators.core_2D_spread: SeedParticle! as SeedParticle2D! +# using ..Operators.core_2D: SeedParticle using ..Architectures: Abstract2DModel, Abstract1DModel, Abstract2DStochasticModel using ..ParticleMesh: OneDGrid, OneDGridNotes, TwoDGrid, TwoDGridNotes @@ -37,8 +38,10 @@ end function plot_state_and_error_points(wave_simulation, gn) plt.plot() + X = (0:(gn.stats.Nx.N-1)).*gn.stats.dx .+ gn.stats.xmin + Y = (0:(gn.stats.Ny.N-1)).*gn.stats.dy .+ gn.stats.ymin energy = get_tot_energy_domain(wave_simulation) - p1 = plt.heatmap(gn.x, gn.y, transpose(wave_simulation.model.State[:, :, 1]), aspect_ratio=:equal, size=(1080, 1080))#,clim=(0,1)) + p1 = plt.heatmap(X, Y, transpose(wave_simulation.model.State[:, :, 1]), aspect_ratio=:equal, size=(1080, 1080))#,clim=(0,1)) plt.plot!(legend=:none, title="total energy = "*string(round(energy,digits=3))*"; max = "*string(round(maximum(wave_simulation.model.State[:,:,1]), @@ -46,8 +49,8 @@ function plot_state_and_error_points(wave_simulation, gn) string(argmax(wave_simulation.model.State[:,:,1])[2])*")", ylabel="y position", xlabel="x position", - xlims=(gn.xmin, gn.xmax), - ylims=(gn.ymin, gn.ymax)) |> display + xlims=(gn.stats.xmin, gn.stats.xmax), + ylims=(gn.stats.ymin, gn.stats.ymax)) |> display end function write_particles_to_csv(wave_model) @@ -89,18 +92,20 @@ main method to run the Simulation sim. Needs time_step! to be defined for the model, and push_state_to_storage! to be defined for the store. """ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) - save_path = sim.model.plot_savepath + @info sim.model.grid.stats + if sim.model isa Abstract2DStochasticModel + save_path = sim.model.plot_savepath - if sim.model.save_particles + if sim.model.save_particles save_path = sim.model.plot_savepath - filename = save_path*"/data/simu_infos.csv" - - Nx = sim.model.grid.Nx - Ny = sim.model.grid.Ny - xmin = sim.model.grid.xmin - xmax = sim.model.grid.xmax - ymin = sim.model.grid.ymin - ymax = sim.model.grid.ymax + filename = save_path*"/data/simu_info.csv" + + Nx = sim.model.grid.stats.Nx.N + Ny = sim.model.grid.stats.Ny.N + xmin = sim.model.grid.stats.xmin + xmax = sim.model.grid.stats.xmax + ymin = sim.model.grid.stats.ymin + ymax = sim.model.grid.stats.ymax lne_source = sim.model.ODEdefaults.lne c_x_source = sim.model.ODEdefaults.c̄_x c_y_source = sim.model.ODEdefaults.c̄_y @@ -123,6 +128,7 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) covariance_init = sim.model.proba_covariance_init data2 = DataFrame(covariance_init, :auto) CSV.write(filename2, data2) + end end start_time_step = time_ns() @@ -207,8 +213,7 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) sim.running = sim.stop_time >= sim.model.clock.time ? true : false if sim.model.plot_steps - gridnotes = TwoDGridNotes(sim.model.grid) - plot_state_and_error_points(sim, gridnotes) + plot_state_and_error_points(sim, sim.model.grid) sec=string(Int64(floor((sim.model.clock.time)/60))) dec=string(Int64(floor(10*(sim.model.clock.time/60-floor((sim.model.clock.time)/60))))) plt.savefig(joinpath([save_path*"/plots/", "energy_plot_no_spread_"*sec*","*dec*".png"])) @@ -310,28 +315,30 @@ function init_particles!(model::Abstract2DStochasticModel; defaults::PP=nothing, end end - gridnotes = TwoDGridNotes(model.grid) - - ParticleCollection = [] - SeedParticle_i = SeedParticle_mapper(SeedParticle2D!, - ParticleCollection, model.State, - model.ODEsystem, nothing, model.ODEsettings, - gridnotes, model.winds, model.ODEsettings.timestep, - model.boundary, model.periodic_boundary) + # gridnotes = TwoDGridNotes(model.grid) + # SeedParticle_i = SeedParticle_mapper(SeedParticle2D!, + # ParticleCollection, model.State, + # model.ODEsystem, nothing, model.ODEsettings, + # gridnotes, model.winds, model.ODEsettings.timestep, + # model.boundary, model.periodic_boundary) - @info typeof(ParticleCollection) - + ParticleCollection = [] model.ParticleCollection = ParticleCollection if defaults isa ParticleDefaults2D - i = Int64(floor((defaults.x - model.grid.xmin) / model.grid.dx)) + 1 - j = Int64(floor((defaults.y - model.grid.ymin) / model.grid.dy)) + 1 - gridnotes = TwoDGridNotes(model.grid) + i = Int64(floor((defaults.x - model.grid.stats.xmin) / model.grid.stats.dx)) + 1 + j = Int64(floor((defaults.y - model.grid.stats.ymin) / model.grid.stats.dy)) + 1 + # gridnotes = TwoDGridNotes(model.grid) if model.angular_spreading_type == "nonparametric" if sum(model.proba_covariance_init)==4e-50 # if "nonparametric" is used, initialize a bigger number of particles at the original perturbation n_part = model.n_particles_launch + ij = CartesianIndices((i,j)) + ij_mesh = model.grid.data[ij] + ij_wind = (model.winds.u(ij_mesh.x, ij_mesh.y, 0.0), + model.winds.v(ij_mesh.x, ij_mesh.y, 0.0) + ) for _ in 1:n_part defaults_temp = deepcopy(defaults) delta_phi = rand() * defaults_temp.angular_σ - 0.5*defaults_temp.angular_σ @@ -340,10 +347,11 @@ function init_particles!(model::Abstract2DStochasticModel; defaults::PP=nothing, defaults_temp.lne += -log(n_part) defaults_temp.c̄_x = c_x defaults_temp.c̄_y = c_y - push!(ParticleCollection, SeedParticle(model.State, + push!(ParticleCollection, SeedParticle2D(model.State, (i,j), model.ODEsystem, defaults_temp, - model.ODEsettings,gridnotes, model.winds, - model.ODEsettings.timestep, model.boundary, + model.ODEsettings, + model.grid.stats,model.grid.ProjetionKernel,model.grid.PropagationCorrection, + ij_mesh[i,j], ij_wind, model.ODEsettings.timestep, model.boundary, model.periodic_boundary)) end else @@ -381,8 +389,8 @@ function init_particles!(model::Abstract2DStochasticModel; defaults::PP=nothing, end elseif defaults isa Array{Any,1} for k in 1:length(defaults) - i = Int64(floor((defaults[k].x - model.grid.xmin) / model.grid.dx)) + 1 - j = Int64(floor((defaults[k].y - model.grid.ymin) / model.grid.dy)) + 1 + i = Int64(floor((defaults[k].x - model.grid.stats.xmin) / model.grid.stats.dx)) + 1 + j = Int64(floor((defaults[k].y - model.grid.stats.ymin) / model.grid.stats.dy)) + 1 gridnotes = OneDGridNotes(model.grid) push!(ParticleCollection, SeedParticle(model.State, (i,j), model.ODEsystem, defaults[k], @@ -482,7 +490,7 @@ function init_particles!(model::Abstract1DModel; defaults::PP=nothing, verbose:: gridnotes, model.winds, model.ODEsettings.timestep, model.boundary, model.periodic_boundary) - map(SeedParticle_i, range(1, length=model.grid.Nx)) + map(SeedParticle_i, range(1, length=model.grid.stats.Nx)) # print(defaults) diff --git a/src/custom_structures.jl b/src/custom_structures.jl index 9b0b63a..a78c47e 100644 --- a/src/custom_structures.jl +++ b/src/custom_structures.jl @@ -1,12 +1,12 @@ module custom_structures -export ParticleInstance1D, ParticleInstance2D, MarkedParticleInstance, AbstractParticleInstance, AbstractMarkedParticleInstance, wni +export ParticleInstance1D, ParticleInstance2D, MarkedParticleInstance, AbstractParticleInstance, AbstractMarkedParticleInstance, StochasticParticleInstance2D, wni using DifferentialEquations: OrdinaryDiffEq.ODEIntegrator using DocStringExtensions using StaticArrays -using ..Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance +using ..Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, AbstractStochasticParticleInstance using ..Architectures: AbstractBoundary # ParticleInstance is the Stucture that carries each particle. @@ -18,6 +18,14 @@ mutable struct ParticleInstance2D <: AbstractParticleInstance on::Bool end +mutable struct StochasticParticleInstance2D <: AbstractStochasticParticleInstance + position_ij::Tuple{Int, Int} + position_xy::Tuple{Float64, Float64} + ODEIntegrator::Union{ODEIntegrator,Nothing} + boundary :: Bool + on::Bool +end + mutable struct ParticleInstance1D <: AbstractParticleInstance position_ij::Int position_xy::Float64 diff --git a/tests/test_case_1.jl b/tests/test_case_1.jl index ce3a685..f80c661 100644 --- a/tests/test_case_1.jl +++ b/tests/test_case_1.jl @@ -14,6 +14,7 @@ using PiCLES.Simulations using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh +using PiCLES.Grids.CartesianGrid: TwoDCartesianGridMesh, TwoDCartesianGridStatistics using PiCLES.Models.GeometricalOpticsModels using Oceananigans.TimeSteppers: Clock, tick! @@ -56,9 +57,9 @@ winds = (u=u, v=v) typeof(winds.u) typeof(winds.u(1e3, 1e3, 11)) -grid = TwoDGrid(22.5e4, 151, 22.5e4, 151) -mesh = TwoDGridMesh(grid, skip=1); -gn = TwoDGridNotes(grid); +grid =TwoDCartesianGridMesh(22.5e4, 151, 22.5e4, 151; periodic_boundary=(false, true)) +# mesh = TwoDGridMesh(grid, skip=1); +# gn = TwoDGridNotes(grid); Revise.retry() From 2d85f154a6ef23961534f13c838678395942b15a Mon Sep 17 00:00:00 2001 From: tomprotin Date: Fri, 16 Jan 2026 17:12:49 +0100 Subject: [PATCH 35/37] removed useless print instruction --- src/Simulations/run.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index cc8fc9c..ebfcee6 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -92,7 +92,6 @@ main method to run the Simulation sim. Needs time_step! to be defined for the model, and push_state_to_storage! to be defined for the store. """ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) - @info sim.model.grid.stats if sim.model isa Abstract2DStochasticModel save_path = sim.model.plot_savepath From c943f313f2a64c1d7160fac5b2de32d6e2e42d1d Mon Sep 17 00:00:00 2001 From: tomprotin Date: Mon, 19 Jan 2026 11:32:33 +0100 Subject: [PATCH 36/37] final modifications to make both versions (stochastic and non-stochastic) work alongside each other --- src/Operators/TimeSteppers.jl | 61 ++++++++++- src/Operators/mapping_2D.jl | 184 ++++++++++++++++++++++++++++++---- src/Simulations/run.jl | 24 +++-- tests/test_case_1.jl | 2 +- 4 files changed, 239 insertions(+), 32 deletions(-) diff --git a/src/Operators/TimeSteppers.jl b/src/Operators/TimeSteppers.jl index 84eae36..10402cb 100644 --- a/src/Operators/TimeSteppers.jl +++ b/src/Operators/TimeSteppers.jl @@ -140,7 +140,7 @@ clock is ticked by Δt callbacks are not implimented yet """ -function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, debug=false) +function time_step!(model::Abstract2DStochasticModel, Δt::Float64; callbacks=nothing, debug=false) # temporary FailedCollection to store failed particles FailedCollection = Vector{AbstractMarkedParticleInstance}([]) @@ -331,6 +331,65 @@ function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, deb tick!(model.clock, Δt) +end + +function time_step!(model::Abstract2DModel, Δt::Float64; callbacks=nothing, debug=false) + + # temporary FailedCollection to store failed particles + FailedCollection = Vector{AbstractMarkedParticleInstance}([]) + + #print("mean energy before advance ", mean_of_state(model), "\n") + if debug + @info "before advance" + @info maximum(model.State[:, :, 1]), maximum(model.State[:, :, 2]), maximum(model.State[:, :, 3]) + model.FailedCollection = FailedCollection + end + + time_step!_advance(model, Δt, FailedCollection) + # @threads for a_particle in model.ParticleCollection[model.ocean_points] + # #@info a_particle.position_ij + # mapping_2D.advance!( a_particle, model.State, FailedCollection, + # model.grid, model.winds, Δt, + # model.ODEsettings.log_energy_maximum, + # model.ODEsettings.wind_min_squared, + # model.periodic_boundary, + # model.ODEdefaults) + # end + + + if debug + print("mean energy after advance ", mean_of_state(model), "\n") + + @info "advanced: " + @info maximum(model.State[:, :, 1]), maximum(model.State[:, :, 2]), maximum(model.State[:, :, 3]) + #@info model.State[8:12, 1], model.State[8:12, 2] + @info model.clock.time, model.ParticleCollection[10].ODEIntegrator.t + @info "winds:", model.winds.u(model.ParticleCollection[10].ODEIntegrator.u[4], model.ParticleCollection[10].ODEIntegrator.u[5], model.ParticleCollection[10].ODEIntegrator.t) + end + + #@printf "re-mesh" + @threads for a_particle in model.ParticleCollection[model.ocean_points] + mapping_2D.remesh!(a_particle, model.State, + model.winds, model.clock.time, + model.ODEsettings, Δt, + model.grid.stats, + model.minimal_state, + model.ODEdefaults) + end + + if debug + @info "remeshed: " + #@info model.State[8:12, 1], model.State[8:12, 2] + @info maximum(model.State[:, :, 1]), maximum(model.State[:, :, 2]), maximum(model.State[:, :, 3]) + @info model.clock.time, model.ParticleCollection[10].ODEIntegrator.t + + end + #print("mean energy after remesh ", mean_of_state(model), "\n") + + # @printf("------- max state E=%.4e cgx=%.4e cgy=%.4e \n", max_energy(model), max_cgx(model), max_cgy(model)) + tick!(model.clock, Δt) + + end function time_step!_advance(model::Abstract2DModel, Δt::Float64, FailedCollection::Vector{AbstractMarkedParticleInstance}) diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index ce0bb5f..b5b591c 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -14,9 +14,15 @@ using ...FetchRelations using ...custom_structures: ParticleInstance1D, ParticleInstance2D, MarkedParticleInstance -using ..core_2D_spread: GetParticleEnergyMomentum, GetVariablesAtVertex, Get_u_FromShared, ResetParticleValues, ParticleDefaults, InitParticleInstance - -using ...Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, AbstractODESettings, StateTypeL1, Abstract2DModel, Abstract2DStochasticModel +using ..core_2D_spread: GetParticleEnergyMomentum as StochasticGetParticleEnergyMomentum +using ..core_2D_spread: GetVariablesAtVertex as StochasticGetVariablesAtVertex +using ..core_2D_spread: Get_u_FromShared as StochasticGet_u_FromShared +using ..core_2D_spread: ResetParticleValues as StochasticResetParticleValues +using ..core_2D_spread: ParticleDefaults as StochasticParticleDefaults +using ..core_2D_spread: InitParticleInstance as StochasticInitParticleInstance +using ..core_2D: GetParticleEnergyMomentum, GetVariablesAtVertex, ParticleDefaults, InitParticleInstance, Get_u_FromShared, ResetParticleValues + +using ...Architectures: AbstractParticleInstance, AbstractStochasticParticleInstance, AbstractMarkedParticleInstance, AbstractODESettings, StateTypeL1, Abstract2DModel, Abstract2DStochasticModel using ...Architectures: Grid2D, CartesianGrid, CartesianGridStatistics, CartesianGrid2D, CartesianGrid1D, AbstractGridStatistics, AbstractGrid, StandardRegular2D_old, MeshGrids, MeshGridStatistics ###### remeshing routines ############ @@ -39,14 +45,14 @@ S Shared array where particles are stored G (TwoDGrid) Grid that defines the nodepositions """ -function ParticleToNode!(PI::AbstractParticleInstance, particlesAtNode::Array{Array{Array{Any,1},1},1}, S::SharedArray, G::TwoDCartesianGridMesh, periodic_boundary::Bool) +function ParticleToNode!(PI::AbstractStochasticParticleInstance, particlesAtNode::Array{Array{Array{Any,1},1},1}, S::SharedArray, G::TwoDCartesianGridMesh, periodic_boundary::Bool) #u[4], u[5] are the x and y positions of the particle #index_positions, weights = PIC.compute_weights_and_index(G, PI.ODEIntegrator.u[4], PI.ODEIntegrator.u[5]) weights_and_index = PIC.compute_weights_and_index_mininal(G, PI.ODEIntegrator.u[4], PI.ODEIntegrator.u[5]) #ui[1:2] .= PI.position_xy - u_state = GetParticleEnergyMomentum(PI.ODEIntegrator.u) + u_state = StochasticGetParticleEnergyMomentum(PI.ODEIntegrator.u) #@show u_state #PIC.push_to_grid!(S, particlesAtNode, PI, u_state , index_positions, weights, G.stats.Nx.N, G.stats.Ny.N , periodic_boundary) @@ -122,11 +128,22 @@ function reset_PI_u!(PI::AbstractParticleInstance; ui::CC) where CC<:Union{Vecto end -function reset_PI_ut!(PI::AbstractParticleInstance; ui::CC, ti::Number, stochas::Bool) where CC <:Union{Vector{Float64},MVector} +function reset_PI_ut!(PI::AbstractStochasticParticleInstance; ui::CC, ti::Number, stochas::Bool) where CC <:Union{Vector{Float64},MVector} # this method keeps the correct time for time varying forcing (~may 2023) if stochas set_u_and_t_stochas!(PI.ODEIntegrator, ui, ti) - @info "called the correct version" + else + @info "called the wrong version" + set_u_and_t!(PI.ODEIntegrator, ui, ti) + end + u_modified!(PI.ODEIntegrator, true) + auto_dt_reset!(PI.ODEIntegrator) +end + +function reset_PI_ut!(PI::AbstractParticleInstance; ui::CC, ti::Number, stochas::Bool) where CC <:Union{Vector{Float64},MVector} + # this method keeps the correct time for time varying forcing (~may 2023) + if stochas + set_u_and_t!(PI.ODEIntegrator, ui, ti) else @info "called the wrong version" set_u_and_t!(PI.ODEIntegrator, ui, ti) @@ -145,9 +162,9 @@ end ######### Core routines for advancing and remeshing """ - advance!(PI::AbstractParticleInstance, S::SharedMatrix{Float64}, G::TwoDGrid, DT::Float64) + advance!(PI::AbstractStochasticParticleInstance, S::SharedMatrix{Float64}, G::TwoDGrid, DT::Float64) """ -function advance!(PI::AbstractParticleInstance, +function advance!(PI::AbstractStochasticParticleInstance, particlesAtNode::Array{Array{Array{Any,1},1},1}, S::StateTypeL1, Failed::Vector{AbstractMarkedParticleInstance}, @@ -158,7 +175,7 @@ function advance!(PI::AbstractParticleInstance, wind_min_squared::Float64, periodic_boundary::Bool, default_particle::PP, - ) where {PP<:Union{ParticleDefaults,Nothing}} + ) where {PP<:Union{StochasticParticleDefaults,Nothing}} #@show PI.position_ij #if ~PI.boundary # if point is not a @@ -204,6 +221,134 @@ function advance!(PI::AbstractParticleInstance, end + elseif ~PI.on #& ~PI.boundary # particle is off, test if there was windsea + + t_end = t_start + DT + wind_end = convert(Tuple{Float64,Float64}, + (winds.u(PI.position_xy[1], PI.position_xy[2], t_end), + winds.v(PI.position_xy[1], PI.position_xy[2], t_end)))::Tuple{Float64,Float64} + + # test if winds where strong enough + if speed_square(wind_end[1], wind_end[2]) >= wind_min_squared + # winds are large eneough, reinit + ui = StochasticResetParticleValues(default_particle, xy, wind_end, DT) + reset_PI_u!(PI, ui =ui) + PI.on = true + end + + else #particle is on and boundary + + #@info "particle is on and boundary" + # particle stays off or is bounaday. do not advance + PI.on=false + return + end + + # # check if integration reached limits or is nan, or what ever. if so, reset + if sum(isnan.(PI.ODEIntegrator.u[1:3])) > 0 + @info "position or Energy is nan, reset" + @info PI.position_ij + @show PI + + t_end = t_start + DT + winds_start = convert( Tuple{Float64,Float64}, + (winds.u(PI.position_xy[1], PI.position_xy[2], t_end), + winds.v(PI.position_xy[1], PI.position_xy[2], t_end)))::Tuple{Float64,Float64} + @show winds_start + + ui = StochasticResetParticleValues(default_particle, xy, winds_start, DT) + @show PI.ODEIntegrator.u + reset_PI_u!(PI, ui=ui) + + elseif sum(isinf.(PI.ODEIntegrator.u[1:3])) > 0 + @info "position or Energy is inf" + @show PI + + winds_start = convert(Tuple{Float64,Float64}, + (winds.u(PI.position_xy[1], PI.position_xy[2], t_start), + winds.v(PI.position_xy[1], PI.position_xy[2], t_start)))::Tuple{Float64,Float64} + + ui = StochasticResetParticleValues(default_particle, xy, winds_start, DT) + reset_PI_u!(PI, ui=ui) + + elseif PI.ODEIntegrator.u[1] > log_energy_maximum + @info "e_max_log is reached" + #@show PI + + # winds_start = convert(Tuple{Float64,Float64}, + # (winds.u(PI.position_xy[1], PI.position_xy[2], t_start), + # winds.v(PI.position_xy[1], PI.position_xy[2], t_start)))::Tuple{Float64,Float64} + + ui = PI.ODEIntegrator.u + ui[1] = log_energy_maximum + # ui = StochasticResetParticleValues(default_particle, xy, winds_start, DT) + reset_PI_u!(PI, ui=ui) + + end + + #if PI.ODEIntegrator.u[1] > -13.0 #ODEs.log_energy_minimum # the minimum enerçy is distributed to 4 neighbouring particles + if PI.on + ParticleToNode!(PI, particlesAtNode, S, Grid, periodic_boundary) + # ParticleToNode!(PI, S, Grid, periodic_boundary) + end + + #return PI +end + +function advance!(PI::AbstractParticleInstance, + S::StateTypeL1, + Failed::Vector{AbstractMarkedParticleInstance}, + Grid::Union{Grid2D,MeshGrids}, + winds::NamedTuple{(:u, :v)}, + DT::Float64, + log_energy_maximum::Float64, + wind_min_squared::Float64, + periodic_boundary::Bool, + default_particle::PP, + ) where {PP<:Union{ParticleDefaults,Nothing}} + #@show PI.position_ij + + #if ~PI.boundary # if point is not a + t_start = copy(PI.ODEIntegrator.t) + add_saveat!(PI.ODEIntegrator, PI.ODEIntegrator.t ) + savevalues!(PI.ODEIntegrator) + + # set the position in particle state vector either to the node position or to the relative position in the CartesianGrid + if typeof(Grid) <: MeshGrids + xy = (0.0,0.0) + # @info "advance: CartesianGrid" + elseif typeof(Grid) <: StandardRegular2D_old + xy = PI.position_xy[1], PI.position_xy[2] + # @info "advance: StandardRegular2D_old" + else + @info "advance: no grid detected" + end + + + # advance particle + if PI.on #& ~PI.boundary # if Particle is on and not boundary + + try + step!(PI.ODEIntegrator, DT, true) + catch e + @printf "error on advancing ODE:\n" + print("- time after fail $(PI.ODEIntegrator.t)\n ") + print("- error message: $(e)\n") + print("- push to failed\n") + print("- state of particle: $(PI.ODEIntegrator.u)\n") + print("- winds are: $(winds.u( PI.ODEIntegrator.u[4], PI.ODEIntegrator.u[5], PI.ODEIntegrator.t))\n") + print("- winds are: $(winds.v( PI.ODEIntegrator.u[4], PI.ODEIntegrator.u[5], PI.ODEIntegrator.t))\n") + push!(Failed, + MarkedParticleInstance( + copy(PI), + copy(PI.ODEIntegrator.t), + copy(PI.ODEIntegrator.u), + PI.ODEIntegrator.sol.retcode + )) + return + + end + elseif ~PI.on #& ~PI.boundary # particle is off, test if there was windsea t_end = t_start + DT @@ -271,8 +416,7 @@ function advance!(PI::AbstractParticleInstance, #if PI.ODEIntegrator.u[1] > -13.0 #ODEs.log_energy_minimum # the minimum enerçy is distributed to 4 neighbouring particles if PI.on - ParticleToNode!(PI, particlesAtNode, S, Grid, periodic_boundary) - # ParticleToNode!(PI, S, Grid, periodic_boundary) + ParticleToNode!(PI, S, Grid, periodic_boundary) end #return PI @@ -356,7 +500,7 @@ function NodeToParticle!(i::Int64, j::Int64, x::Float64, y::Float64, model::Abst nNewParticles = 3 end midParticleInd = Int64(nNewParticles ÷ 2 + 1) - ui = GetVariablesAtVertex(u_state, x, y) + ui = StochasticGetVariablesAtVertex(u_state, x, y) energies = [exp(-(k-midParticleInd)^2/(2*π*midParticleInd)^2) for k in 1:nNewParticles] energies = energies ./ sum(energies) .* exp(ui[1]) @@ -364,8 +508,8 @@ function NodeToParticle!(i::Int64, j::Int64, x::Float64, y::Float64, model::Abst delta_phi = (k-midParticleInd)/midParticleInd*u_state[4] c_x = ui[2] * cos(delta_phi) - ui[3] * sin(delta_phi) c_y = ui[2] * sin(delta_phi) + ui[3] * cos(delta_phi) - z_init = ParticleDefaults(log(energies[k]), c_x, c_y, x, y, u_state[4]/nNewParticles) - push!(model.ParticleCollection,InitParticleInstance(model.ODEsystem, z_init, model.ODEsettings, (i,j), false, true)) + z_init = StochasticParticleDefaults(log(energies[k]), c_x, c_y, x, y, u_state[4]/nNewParticles) + push!(model.ParticleCollection,StochasticInitParticleInstance(model.ODEsystem, z_init, model.ODEsettings, (i,j), false, true)) end elseif model.angular_spreading_type == "nonparametric" nNewParticles = model.n_particles_launch @@ -389,15 +533,15 @@ function NodeToParticle!(i::Int64, j::Int64, x::Float64, y::Float64, model::Abst c_y = model.ParticlesAtNode[i][j][particlesDrawn[k]][3].ODEIntegrator.u[3] spreading = model.ParticlesAtNode[i][j][particlesDrawn[k]][3].ODEIntegrator.u[6] - z_init = ParticleDefaults(log_energy, c_x, c_y, x, y, spreading) - push!(model.ParticleCollection,InitParticleInstance(model.ODEsystem, z_init, model.ODEsettings, (i,j), false, true)) + z_init = StochasticParticleDefaults(log_energy, c_x, c_y, x, y, spreading) + push!(model.ParticleCollection,StochasticInitParticleInstance(model.ODEsystem, z_init, model.ODEsettings, (i,j), false, true)) end end elseif ~PI.boundary & (speed_square(wind_tuple[1], wind_tuple[2]) >= wind_min_squared) #minimal windsea is not big enough but local winds are strong enough #(u_state[1] < exp(e_min_log)) | PI.boundary # test if particle is below energy threshold, or # if particle is at the boundary - ui = ResetParticleValues(default_particle, PI, wind_tuple, DT) # returns winds sea given DT and winds + ui = StochasticResetParticleValues(default_particle, PI, wind_tuple, DT) # returns winds sea given DT and winds reinit!(PI.ODEIntegrator, ui, erase_sol=false, reset_dt=true, reinit_cache=true)#, reinit_callbacks=true) reset_PI_t!(PI, ti=last_t) @@ -405,7 +549,7 @@ function NodeToParticle!(i::Int64, j::Int64, x::Float64, y::Float64, model::Abst elseif PI.boundary & (speed_square(wind_tuple[1], wind_tuple[2]) >= wind_min_squared) # at the boundary, reset particle if winds are strong enough - ui = ResetParticleValues(default_particle, PI, wind_tuple, DT) # returns winds sea given DT and winds + ui = StochasticResetParticleValues(default_particle, PI, wind_tuple, DT) # returns winds sea given DT and winds reinit!(PI.ODEIntegrator, ui, erase_sol=false, reset_dt=true, reinit_cache=true)#, reinit_callbacks=true) reset_PI_t!(PI, ti=last_t) @@ -413,7 +557,7 @@ function NodeToParticle!(i::Int64, j::Int64, x::Float64, y::Float64, model::Abst else # particle is below energy threshold & on boundary - #PI.ODEIntegrator.u = ResetParticleValues(minimal_particle, PI, wind_tuple, DT) + #PI.ODEIntegrator.u = StochasticResetParticleValues(minimal_particle, PI, wind_tuple, DT) # if ~PI.boundary # @info u_state # end diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index ebfcee6..16e0513 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -1,4 +1,5 @@ -using ..Operators.core_2D_spread: SeedParticle as SeedParticle2D +using ..Operators.core_2D_spread: SeedParticle as StochasticSeedParticle2D +using ..Operators.core_2D: SeedParticle as SeedParticle2D using ..Operators.core_2D_spread: ParticleDefaults as ParticleDefaults2D using ..Operators.core_1D: ParticleDefaults as ParticleDefaults1D @@ -136,8 +137,10 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) initialize_simulation!(sim) end - if sim.model.save_particles && length(sim.model.ParticleCollection) > 0 - write_particles_to_csv(sim.model) + if sim.model isa Abstract2DStochasticModel + if sim.model.save_particles && length(sim.model.ParticleCollection) > 0 + write_particles_to_csv(sim.model) + end end #sim.running = true @@ -211,13 +214,14 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) end sim.running = sim.stop_time >= sim.model.clock.time ? true : false - if sim.model.plot_steps - plot_state_and_error_points(sim, sim.model.grid) - sec=string(Int64(floor((sim.model.clock.time)/60))) - dec=string(Int64(floor(10*(sim.model.clock.time/60-floor((sim.model.clock.time)/60))))) - plt.savefig(joinpath([save_path*"/plots/", "energy_plot_no_spread_"*sec*","*dec*".png"])) + if sim.model isa Abstract2DStochasticModel + if sim.model.plot_steps + plot_state_and_error_points(sim, sim.model.grid) + sec=string(Int64(floor((sim.model.clock.time)/60))) + dec=string(Int64(floor(10*(sim.model.clock.time/60-floor((sim.model.clock.time)/60))))) + plt.savefig(joinpath([save_path*"/plots/", "energy_plot_no_spread_"*sec*","*dec*".png"])) + end end - end end_time_step = time_ns() @@ -346,7 +350,7 @@ function init_particles!(model::Abstract2DStochasticModel; defaults::PP=nothing, defaults_temp.lne += -log(n_part) defaults_temp.c̄_x = c_x defaults_temp.c̄_y = c_y - push!(ParticleCollection, SeedParticle2D(model.State, + push!(ParticleCollection, StochasticSeedParticle2D(model.State, (i,j), model.ODEsystem, defaults_temp, model.ODEsettings, model.grid.stats,model.grid.ProjetionKernel,model.grid.PropagationCorrection, diff --git a/tests/test_case_1.jl b/tests/test_case_1.jl index f80c661..2e23d48 100644 --- a/tests/test_case_1.jl +++ b/tests/test_case_1.jl @@ -112,7 +112,7 @@ wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, 0 1e-50 0 0; 0 0 1e-50 0 0 0 0 1e-50], - n_particles_launch=150000 + n_particles_launch=150 ) wave_simulation = Simulation(wave_model, Δt=0.75minutes, stop_time=60minutes) From 8786e749423bb9ffef8f9c0a60a5dc068ec04ea8 Mon Sep 17 00:00:00 2001 From: tomprotin Date: Wed, 18 Feb 2026 10:42:08 +0100 Subject: [PATCH 37/37] testing wind on non parametric method --- src/Operators/core_2D.jl | 2 +- src/Operators/mapping_2D.jl | 10 +- src/ParticleSystems/particle_waves_v6.jl | 20 +++- src/Simulations/run.jl | 10 +- tests/test_case_1.jl | 13 ++- tests/test_case_original_method.jl | 131 +++++++++++++++++++++++ 6 files changed, 173 insertions(+), 13 deletions(-) create mode 100644 tests/test_case_original_method.jl diff --git a/src/Operators/core_2D.jl b/src/Operators/core_2D.jl index ecd32b4..6154486 100644 --- a/src/Operators/core_2D.jl +++ b/src/Operators/core_2D.jl @@ -273,7 +273,7 @@ function InitParticleValues( #c̄_x = u_min[2] #c̄_y = u_min[3] - particle_on = false + particle_on = true end # initialize particle instance based on above devfined values diff --git a/src/Operators/mapping_2D.jl b/src/Operators/mapping_2D.jl index b5b591c..396b47a 100644 --- a/src/Operators/mapping_2D.jl +++ b/src/Operators/mapping_2D.jl @@ -199,9 +199,13 @@ function advance!(PI::AbstractStochasticParticleInstance, if PI.on #& ~PI.boundary # if Particle is on and not boundary try - PI.ODEIntegrator.u[4] += DT*PI.ODEIntegrator.u[2] - PI.ODEIntegrator.u[5] += DT*PI.ODEIntegrator.u[3] - # step!(PI.ODEIntegrator, DT, true) + # PI.ODEIntegrator.u[4] += DT*PI.ODEIntegrator.u[2] + # PI.ODEIntegrator.u[5] += DT*PI.ODEIntegrator.u[3] + before = sqrt(PI.ODEIntegrator.u[2]^2+PI.ODEIntegrator.u[2]^2) + @info PI + step!(PI.ODEIntegrator, DT, true) + after = sqrt(PI.ODEIntegrator.u[2]^2+PI.ODEIntegrator.u[2]^2) + # @info after/before catch e @printf "error on advancing ODE:\n" print("- time after fail $(PI.ODEIntegrator.t)\n ") diff --git a/src/ParticleSystems/particle_waves_v6.jl b/src/ParticleSystems/particle_waves_v6.jl index d2d7339..2871338 100644 --- a/src/ParticleSystems/particle_waves_v6.jl +++ b/src/ParticleSystems/particle_waves_v6.jl @@ -436,11 +436,25 @@ function particle_equations(u_wind, v_wind; γ::Number=0.88, q::Number=-1 / 4.0, #particle_equations::Vector{Number} = [ # energy - dz[1] = +ωₚ .* r_g^2 .* S_cg_tilde + ωₚ .* (Ĩ - D̃) #- c̄ .* G_n, + dz[1] = +ωₚ .* r_g .* S_cg_tilde + ωₚ .* (Ĩ - D̃) #- c̄ .* G_n, # peak group velocity vector - dz[2] = -c̄_x .* ωₚ .* r_g^2 .* S_cg_tilde + c̄_y .* S_dir_tilde #* (-1), - dz[3] = -c̄_y .* ωₚ .* r_g^2 .* S_cg_tilde - c̄_x .* S_dir_tilde #* (1), + # @info "" + # @info "c̄_x = " * string(c̄_x) + # @info "ωₚ = " * string(ωₚ) + # @info "r_g = " * string(r_g) + # @info "S_cg_tilde = " * string(S_cg_tilde) + # @info "c̄_y = " * string(c̄_y) + # @info "S_dir_tilde = " * string(S_dir_tilde) + # total_x = -c̄_x .* ωₚ .* r_g .* S_cg_tilde + c̄_y .* S_dir_tilde + # total_y = -c̄_y .* ωₚ .* r_g .* S_cg_tilde - c̄_x .* S_dir_tilde + # total_tot = sqrt(total_x^2+total_y^2) + # @info "total_x = " * string(total_x) + # @info "total_y = " * string(total_y) + # @info "total_tot = " * string(total_tot) + # @info "" + dz[2] = -c̄_x .* ωₚ .* r_g .* S_cg_tilde + c̄_y .* S_dir_tilde #* (-1), + dz[3] = -c̄_y .* ωₚ .* r_g .* S_cg_tilde - c̄_x .* S_dir_tilde #* (1), # D(c̄_x) ~ -c̄_x .* ωₚ .* r_g^2 .* S_cg_tilde + (c̄_y + 0.001) .* S_dir_tilde, #* (-1), # D(c̄_y) ~ -c̄_y .* ωₚ .* r_g^2 .* S_cg_tilde - (c̄_x + 0.001) .* S_dir_tilde, #* (1), diff --git a/src/Simulations/run.jl b/src/Simulations/run.jl index 16e0513..17c5289 100644 --- a/src/Simulations/run.jl +++ b/src/Simulations/run.jl @@ -60,7 +60,7 @@ function write_particles_to_csv(wave_model) save_path = wave_model.plot_savepath nParticles = wave_model.n_particles_launch - @info wave_model.clock.time/60 + # @info wave_model.clock.time/60 parts = wave_model.ParticleCollection[(end-nParticles+1):end] @@ -181,6 +181,14 @@ function run!(sim; store=false, pickup=false, cash_store=false, debug=false) end # do time step + # l = length(sim.model.ParticleCollection) + # Uxs = [sim.model.ParticleCollection[k].ODEIntegrator.u[2] for k in 1:l] + # Uys = [sim.model.ParticleCollection[k].ODEIntegrator.u[3] for k in 1:l] + # maxUxs = maximum(Uxs) + # maxUys = maximum(Uys) + # @info "maximum(Uxs) = " * string(maxUxs) * " and maximum(Uys) = " * string(maxUys) + # @info "percentage of cell travelled : on x = " * string(maxUxs * sim.Δt / sim.model.grid.stats.dx) * " and on y = " * string(maxUys * sim.Δt / sim.model.grid.stats.dy) + time_step!(sim.model, sim.Δt, debug=debug) if debug & (length(sim.model.FailedCollection) > 0) diff --git a/tests/test_case_1.jl b/tests/test_case_1.jl index 2e23d48..152599a 100644 --- a/tests/test_case_1.jl +++ b/tests/test_case_1.jl @@ -47,8 +47,11 @@ Const_ID = PW.get_I_D_constant() @set Const_ID.γ = 0.88 Const_Scg = PW.get_Scg_constants(C_alpha=- 1.41, C_varphi=1.81e-5) -u_func(x, y, t) = 0. -v_func(x, y, t) = 0. +wind_angle = 3/8*pi +wind_magnitude = 20 + +u_func(x, y, t) = wind_magnitude*cos(wind_angle) +v_func(x, y, t) = wind_magnitude*sin(wind_angle) u(x, y, t) = u_func(x, y, t) v(x, y, t) = v_func(x, y, t) @@ -65,7 +68,7 @@ Revise.retry() # define variables based on particle equation -particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=false); +particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=false, peak_shift=true); # define V4 parameters absed on Const NamedTuple: default_ODE_parameters = (r_g = r_g0, C_α = Const_Scg.C_alpha, @@ -93,7 +96,7 @@ ODE_settings = PW.ODESettings( save_everystep=false) -default_particle = ParticleDefaults(1, 0.0, 22, 112500, 15000., π) +default_particle = ParticleDefaults(5, 0.0, 5.0, 112500., 112500., 2*π) Revise.retry() wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, @@ -115,7 +118,7 @@ wave_model = GeometricalOpticsModels.GeometricalOptics(; grid=grid, n_particles_launch=150 ) -wave_simulation = Simulation(wave_model, Δt=0.75minutes, stop_time=60minutes) +wave_simulation = Simulation(wave_model, Δt=0.75minutes, stop_time=75minutes) initialize_simulation!(wave_simulation) diff --git a/tests/test_case_original_method.jl b/tests/test_case_original_method.jl new file mode 100644 index 0000000..c45f9bd --- /dev/null +++ b/tests/test_case_original_method.jl @@ -0,0 +1,131 @@ +using Pkg +# This will be replaced by the module load in the future +Pkg.activate(".") # Activate the PiCLES package + +using PiCLES +using PiCLES.Operators.core_2D: ParticleDefaults +using PiCLES.Models.WaveGrowthModels2D: WaveGrowth2D +using PiCLES.Simulations +using PiCLES.Grids.CartesianGrid: TwoDCartesianGridMesh, ProjetionKernel, TwoDCartesianGridStatistics + +using PiCLES.ParticleSystems: particle_waves_v5 as PW +using Oceananigans.Units + +# just for simple plotting +import Plots as plt + +# Parameters +U10, V10 = 20.0, 10.0 +DT = 10minutes +r_g0 = 0.85 # ratio of c / c_g (phase velocity/ group velocity). + +# Define wind functions +function ind(x,a,b) + if x>= a && x