├── .gitignore ├── CITATION.cff ├── LICENSE ├── Project.toml ├── README.md ├── benchmark ├── bench01_init_variables.jl ├── bench02_PW5_allocation.jl ├── bench03_single_paticle_2d.jl ├── bench04_test_PW5_solver.jl ├── bench05_PIC2d.jl └── bench06_homogenous_box_brenchmarlk.jl ├── examples ├── _example_eq_v3.jl ├── _example_eq_v4.jl ├── example_00_minimal.jl ├── example_00_minimal_state_vector.jl ├── exmpl_global_projection.jl ├── exmpl_homogenous_box_mprocess.jl └── exmpl_homogenous_box_mthread.jl ├── img └── PiCLES_v0.png ├── src ├── Architectures.jl ├── FetchRelations.jl ├── Grids │ ├── CartesianGrid.jl │ ├── Grids.jl │ ├── SphericalGrid.jl │ ├── TripolarGridMOM6.jl │ ├── files │ │ ├── ocean_hgrid_221123.nc │ │ └── ocean_topo_tx2_3v2_240501.nc │ ├── mask_utils.jl │ ├── mask_utils_test.jl │ └── spherical_grid_corrections.jl ├── Models │ ├── Models.jl │ ├── WaveGrowthModels1D.jl │ └── WaveGrowthModels2D.jl ├── Operators │ ├── Operators.jl │ ├── TimeSteppers.jl │ ├── core_1D.jl │ ├── core_1D_old.jl │ ├── core_2D.jl │ ├── initialize.jl │ ├── mapping_1D.jl │ ├── mapping_2D.jl │ └── utils.jl ├── ParticleInCell.jl ├── ParticleMesh.jl ├── ParticleSystems │ ├── ParticleSystems.jl │ ├── particle_waves_v3.jl │ ├── particle_waves_v3beta.jl │ ├── particle_waves_v4.jl │ └── particle_waves_v5.jl ├── PiCLES.jl ├── Simulations │ ├── Simulations.jl │ ├── run.jl │ ├── simulation.jl │ └── storing.jl ├── Utils │ ├── Debugging.jl │ ├── Initialization.jl │ ├── InputOutput.jl │ ├── ParticleTools.jl │ ├── Utils.jl │ ├── WindEmulator.jl │ ├── convert_particles.jl │ └── convert_particles_1D.jl ├── custom_structures.jl ├── old_structure │ ├── run_1D.jl │ ├── run_1D_manual.jl │ ├── run_2d_manual.jl │ ├── run_collections.jl │ └── run_collections_varying_forcing.jl └── visualization │ ├── Plotting.jl │ ├── global.jl │ ├── movie_2D.jl │ └── plotting_1D.jl └── tests ├── B01_1D_regtest_wave_growth.jl ├── B02_2D_regtest_netCDF.jl ├── B03_2D_regtest_moving_fetch_netCDF.jl ├── S01_grids_Cartesian.jl ├── S01_grids_Tripolar.jl ├── S02_2D_box_mesh_grid.jl ├── S02_2D_box_mesh_grid_single_steps.jl ├── T01_test_PIC_1D.jl ├── T01_test_TemoporalFetchRelatoins.jl ├── T02_single_particle_1d.jl ├── T02_single_particle_1d_compare_PW_versions.jl ├── T02_single_particle_2d.jl ├── T02_single_particle_2d_compare_PW_versions.jl ├── T02_single_particle_2d_great_circle.jl ├── T02_single_paticle_2d_benchmark.jl ├── T03_PIC_propagation_1d.jl ├── T03_PIC_propagation_2d_blob.jl ├── T03_PIC_propagation_2d_land.jl ├── T03_PIC_sphere_aqua.jl ├── T03_PIC_tripolar_aqua.jl ├── T03_PIC_tripolar_land.jl ├── T03_PIC_tripolar_realistic.jl ├── T03_PIC_tripolar_realistic_hires.jl ├── T03_PIC_tripolar_seam_remap.jl ├── T04_2D_box_2d.jl ├── T04_2D_box_diagonal_BC.jl ├── T04_2D_box_rotation.jl ├── T04_2D_growing_decaying_winds.jl ├── T04_2D_on_off_particle_tests.jl ├── T04_2D_reg_test.jl ├── T04_2D_reg_test_large_grid.jl ├── T04_2D_reg_test_netCDF.jl ├── T04_2d_box_diagonal_half_domain.jl ├── T05_2D_distributed_particles.jl ├── T06_layers.jl ├── reg_test_1D.jl ├── runtests.jl └── xProject.toml /.gitignore: -------------------------------------------------------------------------------- 1 | # Files generated by invoking Julia with --code-coverage 2 | *.jl.cov 3 | *.jl.*.cov 4 | 5 | # Files generated by invoking Julia with --track-allocation 6 | *.jl.mem 7 | 8 | # System-specific files and directories generated by the BinaryProvider and BinDeps packages 9 | # They contain absolute paths specific to the host computer, and so should not be committed 10 | deps/deps.jl 11 | deps/build.log 12 | deps/downloads/ 13 | deps/usr/ 14 | deps/src/ 15 | 16 | # Build artifacts for creating documentation generated by the Documenter package 17 | docs/build/ 18 | docs/site/ 19 | 20 | # File generated by Pkg, the package manager, based on a corresponding Project.toml 21 | # It records a fixed state of all packages used by the project. As such, it should not be 22 | # committed for packages, but should be committed for applications that require a static 23 | # environment. 24 | Manifest.toml 25 | 26 | config/config.json 27 | 28 | plots/* 29 | .DS_Store 30 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this software, please cite it as below." 3 | authors: 4 | - family-names: "Hell" 5 | given-names: "Momme Claus" 6 | orcid: "https://orcid.org/0000-0002-5754-3925" 7 | title: "Particle-in-Cell for efficient Swell - PiCLES" 8 | version: 0.1 9 | doi: 10.5281/zenodo.13799205 10 | date-released: 2024-06-06 11 | url: "https://github.com/mochell/PiCLES" 12 | -------------------------------------------------------------------------------- /Project.toml: -------------------------------------------------------------------------------- 1 | name = "PiCLES" 2 | uuid = "79df3bd2-fdbb-4cb7-a58f-f9c8092d6d68" 3 | authors = ["Momme C. Hell"] 4 | version = "0.1.0-DEV" 5 | 6 | [deps] 7 | ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63" 8 | Atom = "c52e3926-4ff0-5f6e-af25-54175e0327b1" 9 | BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" 10 | CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" 11 | Callbacks = "db1e321a-d383-57b4-a664-0144fd54e973" 12 | ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4" 13 | DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 14 | DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" 15 | Dierckx = "39dd38d3-220a-591b-8e3c-4c3a8c710a94" 16 | DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" 17 | DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" 18 | ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" 19 | GEMPIC = "b6d65c3a-4a4e-11e9-25d0-d309dc85ddeb" 20 | GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" 21 | GeoMakie = "db073c08-6b98-4ee5-b6a4-5efafb3259c6" 22 | HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" 23 | IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" 24 | Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" 25 | JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" 26 | Juno = "e5e0dc1b-0480-54bc-9374-aad01c23163d" 27 | LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" 28 | LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 29 | Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" 30 | NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" 31 | Oceananigans = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09" 32 | OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" 33 | Pandas = "eadc2687-ae89-51f9-a5d9-86b5a6373a9c" 34 | Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" 35 | PkgTemplates = "14b8a8f1-9102-5b29-a752-f990bacb7fe1" 36 | Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" 37 | Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" 38 | ProfileView = "c46f51b8-102a-5cf2-8d2c-8597cb0e0da7" 39 | PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" 40 | PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" 41 | Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" 42 | Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" 43 | SharedArrays = "1a1011a3-84de-559e-8e89-a11a2f7dc383" 44 | StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" 45 | Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" 46 | StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" 47 | UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" 48 | WebIO = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29" 49 | 50 | [compat] 51 | julia = "1.10.0" 52 | 53 | [extras] 54 | CPUSummary = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Particle-in-Cell for Efficient Swell - PiCLES ![Build Status](https://github.com/mochell/PiCLES.jl/actions/workflows/CI.yml/badge.svg?branch=main) 2 | PiCLES is a fast and efficient wave model for Earth System Models, using Particle-in-Cell methods for better performance. 3 | 4 | 5 | ![The PiCLES on a Surfboard|200px](./img/PiCLES_v0.png) 6 | 7 | 8 | PiCLES: 9 | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.13799205.svg)](https://doi.org/10.5281/zenodo.13799205) 10 | 11 | Paper draft version: 12 | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.13799253.svg)](https://doi.org/10.5281/zenodo.13799253) 13 | 14 | ## Quick Start 15 | A brief guide on how to use PiCLES. 16 | 17 | ## How to Install 18 | 19 | ### Step 1: Install Julia 20 | 1. Download Julia v1.10.2 or higher from the [official Julia website](https://julialang.org/downloads/). 21 | 2. Follow the installation instructions for your operating system. 22 | 23 | ### Step 2: Download PiCLES Repository 24 | 25 | (Once registered as a Package this will be simpler, sry for the delay) 26 | 27 | 1. Open a terminal or command prompt. 28 | 2. Clone the PiCLES repository using Git: 29 | ``` 30 | git clone https://github.com/mochell/PiCLES.git 31 | ``` 32 | 3. Navigate into the cloned repository directory: 33 | ``` 34 | cd PiCLES 35 | ``` 36 | 37 | ### Step 3: Install Dependencies and Activate Environment 38 | 1. Start Julia by typing `julia` in your terminal within the PiCLES.jl directory. 39 | 2. Activate the project environment: 40 | ```julia 41 | using Pkg 42 | Pkg.activate(".") 43 | ``` 44 | 3. Install the required dependencies: 45 | ```julia 46 | Pkg.instantiate() 47 | ``` 48 | 49 | You are now ready to use PiCLES for your simulations. 50 | 51 | ## How to Run Tests 52 | To run the `T04_2D_reg_test.jl` file from the command line, follow these steps: 53 | 54 | 1. Open a terminal or command prompt. 55 | 2. Navigate to the directory where the `T04_2D_reg_test.jl` file is located. 56 | 3. Start Julia by typing `julia` in your terminal. 57 | 4. In the Julia REPL, include the `T04_2D_reg_test.jl` file: 58 | ```julia 59 | include("T04_2D_reg_test.jl") 60 | ``` 61 | 5. The test will run and display the results in the terminal. 62 | 63 | ## Basic model structure 64 | PiCLES follows the modular model structure from [Oceananigans.jl](https://clima.github.io/OceananigansDocumentation/stable/), but it does not currently share objects. Functionality from Oceananigans does not work in PiCLES. 65 | 66 | A minimal working example is the following [examples/example_00_minimal.jl](examples/example_00_minimal.jl): 67 | 68 | ```julia 69 | using Pkg 70 | # This will be replaced by the module load in the future 71 | Pkg.activate("PiCLES/") # Activate the PiCLES package 72 | 73 | using PiCLES 74 | using PiCLES.Operators.core_2D: ParticleDefaults 75 | using PiCLES.Models.WaveGrowthModels2D: WaveGrowth2D 76 | using PiCLES.Simulations 77 | using PiCLES.Grids.CartesianGrid: TwoDCartesianGridMesh, ProjetionKernel, TwoDCartesianGridStatistics 78 | 79 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 80 | using Oceananigans.Units 81 | 82 | # just for simple plotting 83 | import Plots as plt 84 | 85 | # Parameters 86 | U10, V10 = 10.0, 10.0 87 | DT = 10minutes 88 | r_g0 = 0.85 # ratio of c / c_g (phase velocity/ group velocity). 89 | 90 | # Define wind functions 91 | u(x, y, t) = U10 92 | v(x, y, t) = V10 93 | winds = (u=u, v=v) 94 | 95 | # Define grid 96 | grid = TwoDCartesianGridMesh(100e3, 51, 100e3, 51) 97 | 98 | 99 | # Define ODE parameters 100 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=r_g0) 101 | 102 | # Define particle equations 103 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q); 104 | 105 | # Calculate minimal wind sea based on characteristic winds 106 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT) 107 | 108 | # Define default particle 109 | default_particle = ParticleDefaults(WindSeamin["lne"], WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0) 110 | 111 | # Define ODE settings 112 | ODE_settings = PW.ODESettings( 113 | Parameters=ODEpars, 114 | # define mininum energy threshold 115 | log_energy_minimum=WindSeamin["lne"], 116 | saving_step=DT, 117 | timestep=DT, 118 | total_time=T = 6days, 119 | dt=1e-3, 120 | dtmin=1e-4, 121 | force_dtmin=true) 122 | 123 | # Build wave model 124 | wave_model = WaveGrowth2D(; grid=grid, 125 | winds=winds, 126 | ODEsys=particle_system, 127 | ODEsets=ODE_settings, 128 | periodic_boundary=false, 129 | minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), 130 | movie=true) 131 | 132 | # Build simulation 133 | wave_simulation = Simulation(wave_model, Δt=DT, stop_time=2hour)#1hours) 134 | 135 | # Run simulation 136 | run!(wave_simulation, cash_store=true) 137 | 138 | # Plot initial state 139 | istate = wave_simulation.store.store[end]; 140 | p1 = plt.heatmap(grid.data.x[:,1] / 1e3, grid.data.y[1,:] / 1e3, istate[:, :, 1]) 141 | 142 | ``` 143 | 144 | ## How to Cite 145 | 146 | -------------------------------------------------------------------------------- /benchmark/bench01_init_variables.jl: -------------------------------------------------------------------------------- 1 | using DifferentialEquations 2 | using Plots 3 | using Setfield 4 | 5 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 6 | using PiCLES.Utils: Init_Standard 7 | 8 | import PiCLES: FetchRelations, ParticleTools 9 | using PiCLES.Operators.core_2D: InitParticleInstance 10 | using Oceananigans.Units 11 | 12 | using BenchmarkTools 13 | #using Revise 14 | using Profile 15 | 16 | plot_path_base = "plots/benchmark/" 17 | mkpath(plot_path_base) 18 | 19 | """ 20 | This script is used to benchmark the functions called for (re)-initializing a particle instance. 21 | 22 | """ 23 | 24 | # %% 25 | u(x::Number, y::Number, t::Number) = 10.0 26 | v(x::Number, y::Number, t::Number) = 10.0 27 | 28 | DT = 4hours 29 | ParticleState0, default_ODE_parameters, WindSeamin, Const_ID = Init_Standard(u(0.0, 0.0, 0.0), v(0.0, 0.0, 0.0), DT) 30 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q) 31 | 32 | ODE_settings = PW.ODESettings( 33 | Parameters=default_ODE_parameters, 34 | # define mininum energy threshold 35 | log_energy_minimum=log(WindSeamin["E"]), 36 | #maximum energy threshold 37 | #solver=DP5(), #AutoTsit5(Rosenbrock23()), 38 | log_energy_maximum=log(17), # correcsponds to Hs about 16 m 39 | saving_step=2minutes, 40 | timestep=DT, 41 | total_time=T = 6days, 42 | save_everystep=false, 43 | maxiters=1e4, 44 | adaptive=true, 45 | dt=10,#60*10, 46 | dtmin=1,#60*5, 47 | force_dtmin=true,) 48 | 49 | 50 | # %% 1.) InitParticleInstance 51 | # -- there is not much to do. Most of the allocation is in initializing the ODEIntegrator 52 | ODE_settings = PW.ODESettings( 53 | Parameters=default_ODE_parameters, 54 | # define mininum energy threshold 55 | log_energy_minimum=log(WindSeamin["E"]), 56 | #maximum energy threshold 57 | solver=AutoTsit5(Rosenbrock23()), 58 | log_energy_maximum=log(17), # correcsponds to Hs about 16 m 59 | saving_step=2minutes, timestep=DT, total_time=T = 6days, save_everystep=false, maxiters=1e4, 60 | adaptive=true, dt=10, dtmin=1, force_dtmin=true,) 61 | 62 | #ODE_settings.solver = AutoTsit5(Rosenbrock23()) 63 | @time @allocated PI = InitParticleInstance(particle_system, copy(ParticleState0), ODE_settings, (0, 0), false, true) 64 | 65 | @profview_allocs for i in 1:1000 # Base.Iterators.take(PI.ODEIntegrator, 30) 66 | PI = InitParticleInstance(particle_system, copy(ParticleState0), ODE_settings, (0, 0), false, true) 67 | end 68 | 69 | # %% DP5() 70 | ODE_settings = PW.ODESettings( 71 | Parameters=default_ODE_parameters, 72 | # define mininum energy threshold 73 | log_energy_minimum=log(WindSeamin["E"]), 74 | #maximum energy threshold 75 | solver=DP5(), 76 | log_energy_maximum=log(17), # correcsponds to Hs about 16 m 77 | saving_step=2minutes, timestep=DT, total_time=T = 6days, save_everystep=false, maxiters=1e4, 78 | adaptive=true, dt=10, dtmin=1, force_dtmin=true,) 79 | 80 | #ODE_settings.solver = AutoTsit5(Rosenbrock23()) 81 | @time @allocated PI = InitParticleInstance(particle_system, copy(ParticleState0), ODE_settings, (0, 0), false, true) 82 | # 1st: 0.000216 seconds (159 allocations: 232.000 KiB) 83 | 84 | @profview_allocs for i in 1:10000 # Base.Iterators.take(PI.ODEIntegrator, 30) 85 | PI = InitParticleInstance(particle_system, copy(ParticleState0), ODE_settings, (0, 0), false, true) 86 | end 87 | 88 | 89 | 90 | # %% ------- 2.) windsea 91 | 92 | Revise.retry() 93 | 94 | @time @allocated WindSeamin0 = FetchRelations.get_initial_windsea(u(0.0, 0.0, 0), v(0.0, 0.0, 0), DT / 2) 95 | #org: 0.000339 seconds (60 allocations: 3.094 KiB) 96 | #1st: 0.000102 seconds (8 allocations: 1.938 KiB) 97 | 98 | @time @allocated ui = FetchRelations.get_initial_windsea(u(0.0, 0.0, 0), v(0.0, 0.0, 0), DT / 2, particle_state=true) 99 | # 2nd: 0.000014 seconds (2 allocations: 112 bytes) 100 | 101 | 102 | @profview_allocs for i in 1:10000 # Base.Iterators.take(PI.ODEIntegrator, 30) 103 | #WindSeamin0 = FetchRelations.get_initial_windsea(u(0.0, 0.0, 0), v(0.0, 0.0, 0), DT / 2) 104 | WindSeamin0 = FetchRelations.get_initial_windsea(u(0.0, 0.0, 0), v(0.0, 0.0, 0), DT / 2, particle_state=true) 105 | end 106 | 107 | @benchmark WindSeamin0 = FetchRelations.get_initial_windsea(u(0.0, 0.0, 0), v(0.0, 0.0, 0), DT / 2) 108 | # org: Memory estimate: 3.09 KiB, allocs estimate: 60. 2.843 μs 109 | # 1st: Memory estimate: 1.94 KiB, allocs estimate: 8. 488 ns 110 | 111 | @benchmark WindSeamin0 = FetchRelations.get_initial_windsea(u(0.0, 0.0, 0), v(0.0, 0.0, 0), DT / 2, particle_state=true) 112 | # 2nd: Memory estimate: 112 bytes, allocs estimate: 2. 200 ns 113 | 114 | # %% ------- 3.) set_u_and_t!(PI.ODEIntegrator, ui, last_t) & u_modified!(PI.ODEIntegrator, true) 115 | 116 | function set_u_and_t!(integrator, u_new, t_new) 117 | integrator.u = u_new 118 | integrator.t = t_new 119 | end 120 | 121 | last_t = 600.0 122 | 123 | @benchmark for i in 1:2 # Base.Iterators.take(PI.ODEIntegrator, 30) 124 | set_u_and_t!(PI.ODEIntegrator, ui, last_t) 125 | u_modified!(PI.ODEIntegrator, true) 126 | end 127 | 128 | # Memory estimate: 0 bytes, allocs estimate: 0. 129 | -------------------------------------------------------------------------------- /benchmark/bench04_test_PW5_solver.jl: -------------------------------------------------------------------------------- 1 | #using DifferentialEquations 2 | using OrdinaryDiffEq 3 | using StaticArrays 4 | 5 | 6 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 7 | import PiCLES: FetchRelations, ParticleTools 8 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleValues, InitParticleInstance 9 | using Oceananigans.Units 10 | 11 | 12 | using BenchmarkTools 13 | #using Revise 14 | 15 | using Profile 16 | # debugging: 17 | using ProfileView 18 | 19 | using DataFrames 20 | 21 | # %% 22 | 23 | # % Parameters 24 | initParticleDefaults(s::ParticleDefaults) = [s.lne, s.c̄_x, s.c̄_y, s.x, s.y] 25 | U10, V10 = +10.0, +10.0 26 | 27 | # version 3 28 | r_g0 = 0.85 29 | # function to define constants for grouwth and dissipation 30 | Const_ID = PW.get_I_D_constant() 31 | #@set Const_ID.γ = 0.88 32 | Const_Scg = PW.get_Scg_constants() 33 | 34 | # %% 35 | #u(x, y, t) = 0.01 - U10 * sin(t / (6 * 60 * 60 * 2π)) 36 | #v(x, y, t) = 0.01 - V10 * cos(t / (6 * 60 * 60 * 2π)) 37 | 38 | #u(x, y, t) = - U10 + 0.01 + x * 0 + y * 0 + t *0 39 | #v(x, y, t) = + V10 + 0.01 + x * 0 + y * 0 + t *0 40 | 41 | u(x::Number, y::Number, t::Number) = (10.0 * cos(t / (3 * 60 * 60 * 2π)) + 0.1) + x * 0 + y * 0 42 | v(x::Number, y::Number, t::Number) = -(10.0 * sin(t / (3 * 60 * 60 * 2π)) + 0.1) + x * 0 + y * 0 43 | 44 | # u(x::Number, y::Number, t::Number) = (10 * (t / (3 * 60 * 60 * 2π)) + 0.1) + x * 0 + y * 0 45 | # v(x::Number, y::Number, t::Number) = -(10 * (t / (3 * 60 * 60 * 2π)) + 0.1) + x * 0 + y * 0 46 | DT = 10minutes 47 | 48 | winds = (u=u, v=v) 49 | 50 | # define V4 parameters absed on Const NamedTuple: 51 | default_ODE_parameters = ( 52 | r_g=r_g0, 53 | C_α=Const_Scg.C_alpha, 54 | C_φ=Const_ID.c_β, 55 | C_e=Const_ID.C_e, 56 | g=9.81) 57 | WindSeamin = FetchRelations.get_initial_windsea(u(0.0, 0.0, 0.0), v(0.0, 0.0, 0.0), DT / 2) 58 | z0 = initParticleDefaults(ParticleDefaults(log(WindSeamin["E"]), WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0)) 59 | 60 | z1= z0/2 61 | # %% 62 | Revise.retry() 63 | @time @allocated particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q); 64 | @time @allocated particle_system1 = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q); 65 | 66 | #z = @MVector [0.0, 0.0, 0.0, 1e-4, 0.1] 67 | #z = [0.0, 0.0, 0.0, 1e-4, 0.1]; 68 | @time @allocated particle_system(z0, z0, default_ODE_parameters, 0.1) 69 | @benchmark particle_system(z0, z0, default_ODE_parameters, 0.1) 70 | # Memory estimate: 0 bytes, allocs estimate: 0. 71 | 72 | 73 | @time @allocated problem = ODEProblem(particle_system1, z0, (0.0, 1hour), default_ODE_parameters) 74 | @time @allocated problem2 = ODEProblem(particle_system1, z1, (0.0, 10minutes), default_ODE_parameters) 75 | 76 | @time @allocated sol = solve(problem, save_everystep=false, saveat=200hours, save_on=false) 77 | @time @allocated sol2 = solve(problem2, save_everystep=false, saveat=200hours, save_on=false) 78 | @time @allocated sol2 = solve(problem2, save_everystep=false, saveat=200hours, save_on=false, save_start=false) 79 | 80 | # %% ----- test integration time 81 | 82 | function benchmark_solver(solver_type, T) 83 | 84 | z0 = initParticleDefaults(ParticleDefaults(log(WindSeamin["E"]), WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0)) 85 | problem = ODEProblem(particle_system, z0, (0.0, T), default_ODE_parameters) 86 | trial = @benchmark begin 87 | sol = solve($problem, $solver_type, save_everystep=false, saveat=200hours, save_on=false) 88 | end samples = 2 89 | 90 | return trial 91 | end 92 | 93 | function benchmark_to_dataframe(suite, T, name) 94 | msuite = median(suite) 95 | df = DataFrame(name=name, 96 | Tend=T, 97 | time=msuite.time / 1e6, #ms 98 | memory=msuite.memory / 1024, # KB 99 | allocs=msuite.allocs 100 | ) 101 | return df 102 | end 103 | 104 | function allocation_test(benchmark_tester, time_tuple, solver_tuple; solver_name=("AutoTsit5", "DP5", "Tsit5") ) 105 | 106 | test_collect = DataFrame() 107 | for t in time_tuple, (solver, name) in zip(solver_tuple, solver_name) 108 | @info "Benchmarking $name with T=$t" 109 | suite = benchmark_tester(solver, t) 110 | df = benchmark_to_dataframe(suite, t, name) 111 | test_collect = vcat(test_collect, df) 112 | end 113 | return sort!(test_collect, :time) 114 | 115 | end 116 | 117 | 118 | #allocation_test( (1hour, 10hour, 20hour), (AutoTsit5(Rosenbrock23()),) ; solver_name=(("AutoTsit5"),) ) 119 | Solver_trials = allocation_test(benchmark_solver, (1hour, 10hour, 20hour), (AutoTsit5(Rosenbrock23()), DP5(), Tsit5(),); solver_name=(("AutoTsit5", "DP5", "Tsit5"))) 120 | Solver_trials = sort!(Solver_trials, :name) 121 | 122 | 123 | ## long-term integration 124 | Solver_longerm = allocation_test(benchmark_solver, (10minutes, 30minutes, 1hour, 3hour, 10hour, 30hour), (DP5(), Tsit5(),); solver_name=(("DP5", "Tsit5"))) 125 | Solver_longerm = sort!(Solver_longerm, :name) 126 | 127 | TAutoTsit5 = allocation_test(benchmark_solver, (10minutes, 30minutes, 1hour, 3hour, 10hour, 30hour), (AutoTsit5(Rosenbrock23()),); solver_name=(("AutoTsit5"))) 128 | 129 | # %% manual versions 130 | # 1hour integration 131 | # Memory estimate: 788.92 KiB, allocs estimate: 16668. 921.542 μs 132 | # Memory estimate: 343.98 KiB, allocs estimate: 4464. 133 | 134 | # 10 hour integration 135 | # Memory estimate: 1.65 MiB, allocs estimate: 35774. 1.921 ms 136 | # Memory estimate: 737.17 KiB, allocs estimate: 9590. 137 | 138 | # 20 hour integration 139 | # Memory estimate: 2.02 MiB, allocs estimate: 43687. 2.428 ms 140 | # Memory estimate: 900.02 KiB, allocs estimate: 11713. 141 | 142 | # %% analyse single timestep 143 | 144 | function benchmark_timestep(solver_type, DT) 145 | 146 | z0 = initParticleDefaults(ParticleDefaults(log(WindSeamin["E"]), WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0)) 147 | problem = ODEProblem(particle_system, z0, (0.0,200hours), default_ODE_parameters) 148 | integrator = init(problem, solver_type, saveat=200hours, save_start=false, save_everystep=false) 149 | 150 | @info "Benchmarking $solver_type with DT=$DT" 151 | trial = @benchmark begin 152 | #@info $integrator.alg $DT 153 | step!($integrator, $DT, true); 154 | end samples = 1 155 | 156 | return trial 157 | end 158 | 159 | #benchmark_timestep(AutoTsit5(Rosenbrock23()), 10minutes) 160 | #benchmark_timestep(DP5(), 10minutes) 161 | 162 | #Tester_timestep = allocation_test(benchmark_timestep, (10minutes, 30minutes), (AutoTsit5(Rosenbrock23()), DP5(), Tsit5(),); solver_name=(("AutoTsit5", "DP5",))) 163 | #Tester_timestep 164 | 165 | Tester_timestep = allocation_test(benchmark_timestep, (10minutes,), (DP5(), Tsit5(), Vern7(),); solver_name=(("DP5", "AutoTsit5", "Vern7"))) 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /examples/_example_eq_v3.jl: -------------------------------------------------------------------------------- 1 | 2 | using Plots 3 | using BenchmarkTools 4 | using Revise 5 | using Setfield 6 | 7 | using Statistics 8 | 9 | using JLD2, Printf,IfElse 10 | #using ModelingToolkit: Num, @unpack, @register_symbolic, Symbolics, @named, ODESystem 11 | 12 | # %% 13 | #push!(LOAD_PATH, joinpath(pwd(), "code/")) 14 | using ParticleMesh: OneDGrid, OneDGridNotes 15 | using PiCLES.Operators.core_1D: ParticleDefaults 16 | using PiCLES: Simulation, WindEmulator, WaveGrowthModels1D, FetchRelations 17 | using PiCLES.Simulations 18 | using PiCLES.Plotting 19 | 20 | #using PiCLES.Debugging 21 | using PiCLES.ParticleSystems: particle_waves_v3beta as PW 22 | using PiCLES.ParticleSystems.particle_waves_v4: get_I_D_constant 23 | 24 | 25 | using Oceananigans.TimeSteppers: Clock, tick! 26 | import Oceananigans: fields 27 | using Oceananigans.Units 28 | 29 | # %% 30 | # parametric wind forcing 31 | U10, V = 5, 5 #m/s 32 | # rescale parameters for the right units. 33 | T = 2days#24 * 2 * 60 * 60 # seconds 34 | Lx = 1500kilometer# * 10e3 # km 35 | DT = 20minutes #Float64(20 * 60) # seconds 36 | Nx = 40 37 | dt_ODE_save = 3minutes # 3 min 38 | grid1d = OneDGrid(1e3, Lx - 1e3, Nx) 39 | 40 | r_g0 = 0.85 41 | c_β = 4e-2 42 | C_e0 = (2.35 / r_g0) * 2e-3 * c_β 43 | # function to define constants for grouwth and dissipation 44 | 45 | 46 | @info "Init Forcing Field\n" 47 | # create wind test fucntion 48 | x_scale = 300kilometer 49 | t_scale = 0.6 * 1days #(60 * 60 * 24 * 0.6) 50 | dx = 5kilometer 51 | #fake_winds(x, t) = U10 + x * 0 + t * 0# 52 | #fake_winds(x, t) = 0.01 + t * 0 + U10 * IfElse.ifelse.((x .> Lx / 3.0) & (x .< Lx * 2 / 3.0), 1 + 0 .* x, 0 .* x) * IfElse.ifelse.((t .> T / 4.0), 1 + 0 .* t, 0 .* t) 53 | fake_winds(x, t) = WindEmulator.slopped_blob(x, t, U10, V, T, x_scale, t_scale)# <: WindEmulationFunction2 54 | 55 | wind_grid = WindEmulator.IdealizedWindGrid(fake_winds, (Lx=Lx, T=T), (dx=dx, dt=DT)) 56 | # % define wind forcing globally as interp functions 57 | # and convert to registered_symbolic need foir ODESystem 58 | @register_symbolic u(x, t) 59 | u(x, t) = WindEmulator.wind_interpolator(wind_grid).u(x, t) 60 | 61 | contourf(wind_grid.x / dx, wind_grid.t / DT, transpose(wind_grid.u)) 62 | plot!(xlabel="x", ylabel="time") |> display 63 | 64 | # -------------- start model definition ------------------------- 65 | 66 | # %% Load Particle equations and derive ODE system 67 | Const_ID = get_I_D_constant() 68 | particle_equations = PW.particle_equations(u, u, γ=Const_ID.γ, q=Const_ID.q) 69 | @named particle_system = ODESystem(particle_equations) 70 | 71 | # define variables based on particle equation 72 | t, x, c̄_x, lne, r_g, C_α, g, C_e = PW.init_vars_1D() 73 | 74 | # %% define storing stucture and populate inital conditions 75 | default_ODE_parameters = Dict( r_g => 1 / r_g0, C_α => -1.41, g => 9.81, C_e => C_e0) 76 | 77 | ODE_settings = PW.ODESettings( 78 | Parameters=default_ODE_parameters, 79 | # define mininum energy threshold 80 | log_energy_minimum=log(FetchRelations.Eⱼ(0.1, DT)), 81 | #maximum energy threshold 82 | log_energy_maximum=log(17), # correcsponds to Hs about 16 m 83 | saving_step=dt_ODE_save, 84 | timestep=DT, 85 | total_time=T, 86 | adaptive=true, 87 | dt=1e-3, #60*10, 88 | dtmin=1e-9, #60*5, 89 | force_dtmin=true, 90 | ) 91 | 92 | # Default values for particle 93 | particle_defaults = ParticleDefaults(log(FetchRelations.Eⱼ(0.5, DT)), 2e-1, 0.0) 94 | 95 | # Define wavemodel 96 | wave_model = WaveGrowthModels1D.WaveGrowth1D(; grid=grid1d, 97 | winds=u, 98 | ODEsys=particle_system, 99 | ODEvars=PW.init_vars_1D(), 100 | layers=1, 101 | ODEsets=ODE_settings, # ODE_settings 102 | ODEdefaults=particle_defaults, # default_ODE_parameters 103 | periodic_boundary=false, 104 | boundary_type="default" #"wind_sea" 105 | ) 106 | 107 | # %% initialize Simulation 108 | wave_simulation = Simulation(wave_model, Δt=20minutes, stop_time=6hours) 109 | initialize_simulation!(wave_simulation)#, particle_initials=nothing)#wave_model.ODEdefaults) 110 | 111 | # run simulation 112 | run!(wave_simulation, store=false, cash_store=true, debug=false) 113 | @info "... finished\n" 114 | 115 | Plotting.plot_results(wave_simulation) 116 | -------------------------------------------------------------------------------- /examples/_example_eq_v4.jl: -------------------------------------------------------------------------------- 1 | 2 | using Plots 3 | using BenchmarkTools 4 | using Revise 5 | using Setfield 6 | 7 | using Statistics 8 | 9 | using JLD2, Printf,IfElse 10 | # using ModelingToolkit: Num, @unpack, @register_symbolic, Symbolics, @named, ODESystem 11 | 12 | # %% 13 | 14 | using ParticleMesh: OneDGrid, OneDGridNotes 15 | using PiCLES.Operators.core_1D: ParticleDefaults 16 | using PiCLES: Simulation, WindEmulator, WaveGrowthModels1D, FetchRelations 17 | using PiCLES.Simulations 18 | using PiCLES.Plotting 19 | 20 | #using PiCLES.Debugging 21 | using PiCLES.ParticleSystems: particle_waves_v4 as PW 22 | 23 | using Oceananigans.TimeSteppers: Clock, tick! 24 | import Oceananigans: fields 25 | using Oceananigans.Units 26 | 27 | # %% 28 | # parametric wind forcing 29 | U10, V = 5, 5 #m/s 30 | # rescale parameters for the right units. 31 | T = 2days#24 * 2 * 60 * 60 # seconds 32 | Lx = 1500kilometer# * 10e3 # km 33 | DT = 20minutes #Float64(20 * 60) # seconds 34 | Nx = 40 35 | dt_ODE_save = 3minutes # 3 min 36 | grid1d = OneDGrid(1e3, Lx - 1e3, Nx) 37 | 38 | r_g0 = 0.85 39 | # function to define constants for grouwth and dissipation 40 | Const_ID = PW.get_I_D_constant() 41 | #@set Const_ID.γ = 0.88 42 | Const_Scg = PW.get_Scg_constants() 43 | 44 | 45 | @info "Init Forcing Field\n" 46 | # create wind test fucntion 47 | x_scale = 300kilometer 48 | t_scale = 0.6 * 1days #(60 * 60 * 24 * 0.6) 49 | dx = 5kilometer 50 | #fake_winds(x, t) = U10 + x * 0 + t * 0# 51 | #fake_winds(x, t) = 0.01 + t * 0 + U10 * IfElse.ifelse.((x .> Lx / 3.0) & (x .< Lx * 2 / 3.0), 1 + 0 .* x, 0 .* x) * IfElse.ifelse.((t .> T / 4.0), 1 + 0 .* t, 0 .* t) 52 | fake_winds(x, t) = WindEmulator.slopped_blob(x, t, U10, V, T, x_scale, t_scale)# <: WindEmulationFunction2 53 | 54 | wind_grid = WindEmulator.IdealizedWindGrid(fake_winds, (Lx=Lx, T=T), (dx=dx, dt=DT)) 55 | # % define wind forcing globally as interp functions 56 | # and convert to registered_symbolic need foir ODESystem 57 | @register_symbolic u(x, t) 58 | u(x, t) = WindEmulator.wind_interpolator(wind_grid).u(x, t) 59 | 60 | contourf(wind_grid.x / dx, wind_grid.t / DT, transpose(wind_grid.u)) 61 | plot!(xlabel="x", ylabel="time") |> display 62 | 63 | # -------------- start model definition ------------------------- 64 | 65 | # %% Load Particle equations and derive ODE system 66 | particle_equations = PW.particle_equations(u, γ=Const_ID.γ, q=Const_ID.q) 67 | @named particle_system = ODESystem(particle_equations) 68 | 69 | # define variables based on particle equation 70 | t, x, c̄_x, lne, r_g, C_α, g, C_e = PW.init_vars_1D() 71 | 72 | # %% define storing stucture and populate inital conditions 73 | default_ODE_parameters = Dict(r_g => r_g0, C_α => Const_Scg.C_alpha, C_e => Const_ID.C_e) 74 | 75 | ODE_settings = PW.ODESettings( 76 | Parameters=default_ODE_parameters, 77 | # define mininum energy threshold 78 | log_energy_minimum=log(FetchRelations.Eⱼ(0.1, DT)), 79 | #maximum energy threshold 80 | log_energy_maximum=log(17), # correcsponds to Hs about 16 m 81 | saving_step=dt_ODE_save, 82 | timestep=DT, 83 | total_time=T, 84 | adaptive=true, 85 | dt=1e-3, #60*10, 86 | dtmin=1e-9, #60*5, 87 | force_dtmin=true, 88 | ) 89 | 90 | # Default values for particle 91 | particle_defaults = ParticleDefaults(log(FetchRelations.Eⱼ(0.5, DT)), 2e-1, 0.0) 92 | 93 | # Define wavemodel 94 | wave_model = WaveGrowthModels1D.WaveGrowth1D(; grid=grid1d, 95 | winds=u, 96 | ODEsys=particle_system, 97 | ODEvars=PW.init_vars_1D(), 98 | layers=1, 99 | ODEsets=ODE_settings, # ODE_settings 100 | ODEdefaults=particle_defaults, # default_ODE_parameters 101 | periodic_boundary=false, 102 | boundary_type="default" #"wind_sea" 103 | ) 104 | 105 | # %% initialize Simulation 106 | wave_simulation = Simulation(wave_model, Δt=20minutes, stop_time=40hours) 107 | initialize_simulation!(wave_simulation)#, particle_initials=nothing)#wave_model.ODEdefaults) 108 | 109 | # run simulation 110 | run!(wave_simulation, store=false, cash_store=true, debug=false) 111 | @info "... finished\n" 112 | 113 | Plotting.plot_results(wave_simulation) 114 | 115 | plot_path_base = "plots/PW4/1D/" 116 | mkpath(plot_path_base) 117 | savefig(joinpath(plot_path_base, "PW3_vs_PW4.png")) 118 | 119 | -------------------------------------------------------------------------------- /examples/example_00_minimal.jl: -------------------------------------------------------------------------------- 1 | using Pkg 2 | # this will be replace by the module load in the future 3 | Pkg.activate("PiCLES/") # Activate the PiCLES package 4 | 5 | using PiCLES 6 | using PiCLES.Operators.core_2D: ParticleDefaults 7 | using PiCLES.Models.WaveGrowthModels2D: WaveGrowth2D 8 | using PiCLES.Simulations 9 | using PiCLES.Grids.CartesianGrid: TwoDCartesianGridMesh, ProjetionKernel, TwoDCartesianGridStatistics 10 | 11 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 12 | using Oceananigans.Units 13 | 14 | # just for simple plotting 15 | import Plots as plt 16 | 17 | # Parameters 18 | U10, V10 = 10.0, 10.0 19 | DT = 10minutes 20 | r_g0 = 0.85 # ratio of c / c_g (phase velocity/ group velocity). 21 | 22 | # Define wind functions 23 | u(x, y, t) = U10 24 | v(x, y, t) = V10 25 | winds = (u=u, v=v) 26 | 27 | # Define grid 28 | grid = TwoDCartesianGridMesh(100e3, 51, 100e3, 51) 29 | 30 | 31 | # Define ODE parameters 32 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=r_g0) 33 | 34 | # Define particle equations 35 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q); 36 | 37 | # Calculate minimal windsea based on characteristic winds 38 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT) 39 | 40 | # Define default particle 41 | default_particle = ParticleDefaults(WindSeamin["lne"], WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0) 42 | 43 | # Define ODE settings 44 | ODE_settings = PW.ODESettings( 45 | Parameters=ODEpars, 46 | log_energy_minimum=WindSeamin["lne"], # define mininum energy threshold 47 | saving_step=DT, 48 | timestep=DT, 49 | total_time=T = 6days, 50 | dt=1e-3, #60*10, 51 | dtmin=1e-4, #60*5, 52 | force_dtmin=true) 53 | 54 | # Build wave model 55 | wave_model = WaveGrowth2D(; grid=grid, 56 | winds=winds, 57 | ODEsys=particle_system, 58 | ODEsets=ODE_settings, 59 | periodic_boundary=false, 60 | minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), 61 | movie=true) 62 | 63 | # Build simulation 64 | wave_simulation = Simulation(wave_model, Δt=DT, stop_time=2hour)#1hours) 65 | 66 | # Run simulation 67 | run!(wave_simulation, cash_store=true) 68 | 69 | # Plot initial state 70 | istate = wave_simulation.store.store[end]; 71 | p1 = plt.heatmap(grid.data.x[:,1] / 1e3, grid.data.y[1,:] / 1e3, istate[:, :, 1]) 72 | -------------------------------------------------------------------------------- /examples/example_00_minimal_state_vector.jl: -------------------------------------------------------------------------------- 1 | using Pkg 2 | # this will be replace by the module load in the future 3 | Pkg.activate("PiCLES/") # Activate the PiCLES package 4 | 5 | using PiCLES 6 | using PiCLES.Operators.core_2D: ParticleDefaults 7 | using PiCLES.Models.WaveGrowthModels2D: WaveGrowth2D 8 | using PiCLES.Simulations 9 | using PiCLES.Grids.CartesianGrid: TwoDCartesianGridMesh, ProjetionKernel, TwoDCartesianGridStatistics 10 | 11 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 12 | using Oceananigans.Units 13 | 14 | # just for simple plotting 15 | import Plots as plt 16 | 17 | 18 | # %% 19 | speed(x::Float64, y::Float64) = sqrt(x^2 + y^2) 20 | 21 | function PartitionOutput(State) 22 | 23 | energy = State[:, :, 1] # Energy 24 | m_1 = State[:, :, 2] # Zonal momentum 25 | m_2 = State[:, :, 3] # Meridional momentum 26 | 27 | # m_0 - Hs 28 | moment_0_hs = 4 * sqrt.(energy) 29 | # m_1 - dummy version 30 | moment_1 = energy * 0.1 31 | # m_2 - dummy version 32 | moment_2 = energy * 0.01 33 | 34 | m_amp = speed.(m_1, m_2) 35 | 36 | # T_p - dummy 37 | # check the use of r_g 38 | T_p = energy * 0 .+ 10.0 39 | 40 | # c_g vector 41 | c_x = m_1 .* energy ./ (2 * m_amp^2) 42 | c_y = m_2 .* energy ./ (2 * m_amp^2) 43 | 44 | # c stokes vector - dummy 45 | u_stokes_x = c_x * 0.1 46 | u_stokes_y = c_y * 0.1 47 | 48 | 49 | output_array = cat(moment_0_hs, 50 | moment_1, moment_2, 51 | T_p, 52 | c_x, c_y, 53 | u_stokes_x, u_stokes_y, dims=3) 54 | 55 | return output_array 56 | 57 | end 58 | # %% 59 | 60 | # Parameters 61 | U10, V10 = 10.0, 10.0 62 | DT = 10minutes 63 | r_g0 = 0.85 # ratio of c / c_g (phase velocity/ group velocity). 64 | 65 | # Define wind functions 66 | u(x, y, t) = U10 67 | v(x, y, t) = V10 68 | winds = (u=u, v=v) 69 | 70 | 71 | # ---------- initialize start --------- 72 | # Define grid 73 | grid = TwoDCartesianGridMesh(100e3, 51, 100e3, 51) 74 | 75 | 76 | # Define ODE parameters 77 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=r_g0) 78 | 79 | # Define particle equations 80 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q); 81 | 82 | # Calculate minimal windsea based on characteristic winds 83 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT) 84 | 85 | # Define default particle 86 | default_particle = ParticleDefaults(WindSeamin["lne"], WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0) 87 | 88 | # Define ODE settings 89 | ODE_settings = PW.ODESettings( 90 | Parameters=ODEpars, 91 | log_energy_minimum=WindSeamin["lne"], # define mininum energy threshold 92 | saving_step=DT, 93 | timestep=DT, 94 | total_time=T = 6days, 95 | dt=1e-3, #60*10, 96 | dtmin=1e-4, #60*5, 97 | force_dtmin=true) 98 | 99 | # Build wave model 100 | wave_model = WaveGrowth2D(; grid=grid, 101 | winds=winds, 102 | ODEsys=particle_system, 103 | ODEsets=ODE_settings, 104 | periodic_boundary=false, 105 | minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), 106 | movie=true) 107 | 108 | # Build simulation 109 | wave_simulation = Simulation(wave_model, Δt=DT, stop_time=2hour)#1hours) 110 | # ---------- initialize end --------- 111 | 112 | # ---------- run start --------- 113 | # Run simulation 114 | run!(wave_simulation, cash_store=true) 115 | 116 | # output per time step for a single partition 117 | SinglePartitionOutput = PartitionOutput(wave_model.State) 118 | # ---------- run end --------- 119 | 120 | ### some explanations 121 | # wave model State vector: 122 | wave_model.State 123 | wave_model.State[:, :, 1] # Energy 124 | wave_model.State[:, :, 2] # Zonal momentum 125 | wave_model.State[:, :, 3] # Meridional momentum 126 | 127 | 128 | # Dimensions 129 | # this will we change when PiCLES updated to more advanced grid module 130 | grid.data.x 131 | grid.data.y 132 | 133 | # plot state 134 | istate = wave_simulation.store.store[end]; 135 | p1 = plt.heatmap(grid.data.x[:, 1] / 1e3, grid.data.y[1, :] / 1e3, SinglePartitionOutput[:, :, 1], title="Hs (m)", xlabel="x (km)", ylabel="y (km)") 136 | -------------------------------------------------------------------------------- /examples/exmpl_global_projection.jl: -------------------------------------------------------------------------------- 1 | using Pkg 2 | Pkg.activate("PiCLES/") 3 | 4 | using CairoMakie, GeoMakie 5 | 6 | fig = Figure() 7 | ga = GeoAxis( 8 | fig[1, 1]; # any cell of the figure's layout 9 | dest="+proj=wintri", # the CRS in which you want to plot 10 | ) 11 | lines!(ga, GeoMakie.coastlines()) # plot coastlines from Natural Earth as a reference 12 | # You can plot your data the same way you would in Makie 13 | scatter!(ga, -120:15:120, -60:7.5:60; color=-60:7.5:60, strokecolor=(:black, 0.2)) 14 | fig 15 | 16 | 17 | 18 | # %% 19 | 20 | lons = -180:180 21 | lats = -90:90 22 | field = [exp(cosd(l)) + 3(y / 90) for l in lons, y in lats] 23 | 24 | 25 | function simple_geomap(lons, lats, field) 26 | fig = Figure() 27 | ax = GeoAxis(fig[1, 1]) 28 | sp = surface!(ax, lons, lats, field; shading=NoShading) 29 | # lines!(ax, GeoMakie.coastlines()) 30 | 31 | land = GeoMakie.land() 32 | 33 | poly!(ax, land, color=:black) 34 | 35 | fig 36 | end 37 | 38 | simple_geomap(lons, lats, field) 39 | 40 | # %% 41 | 42 | using GeoMakie, CairoMakie 43 | 44 | xs = LinRange(311.9, 391.1, 30) 45 | ys = LinRange(-23.6, 24.8, 20) 46 | 47 | us = @. 1 * (2 * cos(2 * deg2rad(xs) + 3 * deg2rad(ys' + 30))^2) 48 | vs = @. 2 * cos(6 * deg2rad(xs)) .+ ys' * 0 # that last part is just to establish the shape 49 | 50 | 51 | pole_longitude = 177.5 52 | pole_latitude = 37.5 53 | arrow_crs = "+proj=ob_tran +o_proj=latlon +o_lon_p=0 +o_lat_p=$(pole_latitude) +lon_0=$(180+pole_longitude) +to_meter=$(deg2rad(1) * 6378137.0)" 54 | 55 | f, a, p = arrows( 56 | xs, ys, us, vs; 57 | arrowsize=4, 58 | source=arrow_crs, 59 | axis=(; type=GeoAxis, dest="+proj=ortho +lon_0=-10 +lat_0=45") 60 | ) 61 | 62 | # %% 63 | ep = surface!(a, 64 | -180 .. 180, -90 .. 90, 65 | zeros(axes(rotr90(GeoMakie.earth()))); 66 | shading=NoShading, color=rotr90(GeoMakie.earth()) 67 | ) 68 | 69 | translate!(ep, 0, 0, -1) 70 | f -------------------------------------------------------------------------------- /examples/exmpl_homogenous_box_mthread.jl: -------------------------------------------------------------------------------- 1 | using Pkg 2 | Pkg.activate("PiCLES/") 3 | 4 | using Base.Threads 5 | @info "Num. of threads", nthreads() 6 | 7 | # import Plots as plt 8 | using Setfield 9 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 10 | 11 | import PiCLES: FetchRelations, ParticleTools 12 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 13 | using PiCLES.Simulations 14 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 15 | 16 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 17 | using PiCLES.Models.WaveGrowthModels2D 18 | 19 | using Oceananigans.TimeSteppers: Clock, tick! 20 | import Oceananigans: fields 21 | using Oceananigans.Units 22 | import Oceananigans.Utils: prettytime 23 | 24 | using PiCLES.Architectures 25 | #using GLMakie 26 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 27 | 28 | #using ProfileView 29 | using BenchmarkTools 30 | #using Revise 31 | 32 | using Profile 33 | # debugging: 34 | using ProfileView 35 | 36 | @info "precompiled!" 37 | # %% 38 | save_path = "plots/examples/homogenous_box/" 39 | mkpath(save_path) 40 | 41 | # % Parameters 42 | U10, V10 = 10.0, 10.0 43 | 44 | DT = 30minutes 45 | # version 3 46 | r_g0 = 0.85 47 | 48 | # function to define constants 49 | Const_ID = PW.get_I_D_constant() 50 | @set Const_ID.γ = 0.88 51 | Const_Scg = PW.get_Scg_constants(C_alpha=-1.41, C_varphi=1.81e-5) 52 | 53 | 54 | u(x::Number, y::Number, t::Number) = 10.0 #* sin(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) 55 | v(x::Number, y::Number, t::Number) = 10.0 #* cos(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) 56 | 57 | winds = (u=u, v=v) 58 | 59 | grid = TwoDGrid(100e3, 51, 100e3, 51) 60 | #grid = TwoDGrid(20e3, 21, 20e3, 21) 61 | mesh = TwoDGridMesh(grid, skip=1) 62 | gn = TwoDGridNotes(grid) 63 | #Revise.retry() 64 | 65 | 66 | # define variables based on particle equation 67 | particle_system = PW.particle_equations(u, v, γ=0.88, q=Const_ID.q, input=true, dissipation=true) 68 | #particle_equations = PW3.particle_equations_vec5(u, v, u, v, γ=0.88, q=Const_ID.q); 69 | 70 | # define V4 parameters absed on Const NamedTuple: 71 | default_ODE_parameters = (r_g=r_g0, C_α=Const_Scg.C_alpha, 72 | C_φ=Const_ID.c_β, C_e=Const_ID.C_e, g=9.81) 73 | 74 | # define setting and standard initial conditions 75 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT) 76 | #WindSeamin = FetchRelations.MinimalWindsea(u(0, 0, 0), v(0, 0, 0), DT / 2) 77 | #WindSeamin = FetchRelations.get_initial_windsea(u(0, 0, 0), v(0, 0, 0), DT/5) 78 | lne_local = log(WindSeamin["E"]) 79 | cg_u_local = WindSeamin["cg_bar_x"] 80 | cg_v_local = WindSeamin["cg_bar_y"] 81 | 82 | ODE_settings = PW.ODESettings( 83 | Parameters=default_ODE_parameters, 84 | # define mininum energy threshold 85 | log_energy_minimum=lne_local,#log(FetchRelations.Eⱼ(0.1, DT)), 86 | #maximum energy threshold 87 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 88 | saving_step=300hours, 89 | timestep=DT, 90 | total_time=T = 6days, 91 | adaptive=true, 92 | dt=1e-3, #60*10, 93 | dtmin=1e-4, #60*5, 94 | force_dtmin=true, 95 | callbacks=nothing, 96 | save_everystep=false) 97 | 98 | 99 | default_particle = ParticleDefaults(lne_local, cg_u_local, cg_v_local, 0.0, 0.0) 100 | 101 | #Revise.retry() 102 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 103 | winds=winds, 104 | ODEsys=particle_system, 105 | ODEsets=ODE_settings, # ODE_settings 106 | ODEinit_type="wind_sea", # default_ODE_parameters 107 | periodic_boundary=false, 108 | boundary_type="same", 109 | #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), 110 | movie=true); 111 | 112 | 113 | Revise.retry() 114 | 115 | #global wave_model.ParticleCollection 116 | ### build Simulation 117 | #wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=4hours)#1hours) 118 | wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=1hour);#1hours) 119 | initialize_simulation!(wave_simulation) 120 | 121 | # # %% single time steps 122 | # import PiCLES.Operators.TimeSteppers: time_step! 123 | # for i in 1:3 124 | # wave_simulation.model.State .= 0.0 125 | # @time time_step!(wave_simulation.model, wave_simulation.Δt, debug=false) 126 | # #time_step!(wave_simulation.model, wave_simulation.Δt, debug=false) 127 | # istate = wave_simulation.model.State 128 | # p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, istate[:, :, 1]) 129 | # display(p1) 130 | # sleep(0.5) 131 | # end 132 | # # %% 133 | 134 | Revise.retry() 135 | run!(wave_simulation, cash_store=false, debug=false); 136 | 137 | # %% 138 | reset_simulation!(wave_simulation) 139 | wave_simulation.stop_time = 20minutes 140 | #ProfileView.@profview run!(wave_simulation, cash_store=false, debug=false); 141 | 142 | @time @allocated run!(wave_simulation, cash_store=false, debug=false); 143 | # single thread: 144 | # org: 01/13/2024: 5.926792 seconds (54.35 M allocations: 1.434 GiB, 12.16% gc time) 145 | # 1st: 01/15/2024: 0.178086 seconds (573.16 k allocations: 37.163 MiB) 146 | # 4 threads: 0.105369 seconds (573.25 k allocations: 37.172 MiB) 147 | # 8 threads: 0.156241 seconds (573.37 k allocations: 37.185 MiB) 148 | 149 | 150 | wave_simulation.stop_time = 40minutes 151 | @time @allocated run!(wave_simulation, cash_store=false, debug=false); 152 | # single thread: 153 | # org: 01/132024: 2.322934 seconds (18.59 M allocations: 566.626 MiB, 10.23% gc time) 154 | # 1st: 0.163212 seconds (368.23 k allocations: 23.530 MiB, 40.60% gc time) 155 | # 4 threads: 0.065552 seconds (368.29 k allocations: 23.536 MiB) 156 | # 8 threads: 0.092020 seconds (368.37 k allocations: 23.544 MiB) 157 | 158 | wave_simulation.stop_time = 80minutes 159 | ProfileView.@profview run!(wave_simulation, cash_store=false, debug=false); 160 | 161 | wave_simulation.stop_time = 120minutes 162 | @profview_allocs run!(wave_simulation, cash_store=false, debug=false); 163 | -------------------------------------------------------------------------------- /img/PiCLES_v0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mochell/PiCLES/ecddc4b2e3564469eb02d607608c0cac06e9dbc4/img/PiCLES_v0.png -------------------------------------------------------------------------------- /src/Architectures.jl: -------------------------------------------------------------------------------- 1 | module Architectures 2 | 3 | using SharedArrays 4 | using StaticArrays 5 | 6 | 7 | export AbstractGrid, AbstractODESettings, AbstractParticleInstance, AbstractMarkedParticleInstance, Abstract1DModel, Abstract2DModel, AbstractModel, AbstractStore, AbstractParticleSystem, StateTypeL1, IDConstantsInstance, ScgConstantsInstance, CartesianGrid, CartesianGrid1D, CartesianGrid2D, TripolarGrid, Grid2D, MeshGrids, MeshGridStatistics 8 | 9 | export StandardRegular1D_old, StandardRegular2D_old 10 | 11 | export AbstractBoundary, BoundaryType 12 | 13 | abstract type AbstractGrid end 14 | 15 | abstract type AbstractGridStatistics <: AbstractGrid end 16 | 17 | abstract type CartesianGrid <: AbstractGrid end 18 | abstract type CartesianGrid1D <: CartesianGrid end 19 | abstract type CartesianGrid2D <: CartesianGrid end 20 | abstract type CartesianGridStatistics <: AbstractGridStatistics end 21 | 22 | #Spherical Grids 23 | abstract type SphericalGrid <: AbstractGrid end 24 | abstract type SphericalGrid2D <: SphericalGrid end 25 | abstract type SphericalGridStatistics <: AbstractGridStatistics end 26 | 27 | abstract type TripolarGrid <: AbstractGrid end 28 | # abstract type MOM6_2_3 <: TripolarGrid end 29 | abstract type TripolarGridStatistics <: AbstractGridStatistics end 30 | 31 | abstract type StandardRegular1D_old <: AbstractGrid end 32 | abstract type StandardRegular2D_old <: AbstractGrid end 33 | 34 | Grid2D = Union{CartesianGrid2D,SphericalGrid2D,StandardRegular2D_old} 35 | 36 | # used for model intialization 37 | MeshGrids = Union{CartesianGrid2D,TripolarGrid,SphericalGrid2D} 38 | MeshGridStatistics = Union{CartesianGridStatistics,TripolarGridStatistics,SphericalGridStatistics} 39 | 40 | abstract type AbstractODESettings end 41 | abstract type AbstractParticleInstance end 42 | abstract type AbstractMarkedParticleInstance end 43 | 44 | abstract type IDConstantsInstance end 45 | abstract type ScgConstantsInstance end 46 | 47 | 48 | """ 49 | AbstractModel 50 | Abstract supertype for models. 51 | """ 52 | abstract type AbstractModel{TS} end 53 | 54 | abstract type Abstract1DModel <: AbstractModel{Nothing} end 55 | abstract type Abstract2DModel <: AbstractModel{Nothing} end 56 | 57 | #All posiible types of a single-layer StateVectors 58 | StateTypeL1 = Union{SharedArray{Float64,3},MArray} 59 | 60 | abstract type AbstractStore end 61 | 62 | abstract type AbstractParticleSystem end 63 | 64 | 65 | # %% abstract Boundary Integer types 66 | abstract type AbstractBoundary <: Integer end 67 | Base.show(io::IO, obj::AbstractBoundary) = print(io, "Int=", obj.N, " ", typeof(obj)) 68 | 69 | BoundaryType = Union{AbstractBoundary,Integer} 70 | 71 | 72 | end -------------------------------------------------------------------------------- /src/Grids/CartesianGrid.jl: -------------------------------------------------------------------------------- 1 | module CartesianGrid 2 | 3 | using ...Architectures: AbstractGrid, AbstractGridStatistics, CartesianGrid1D, CartesianGrid2D, CartesianGridStatistics, AbstractBoundary, BoundaryType 4 | using ...custom_structures: N_Periodic, N_NonPeriodic, N_TripolarNorth 5 | 6 | #using LinearAlgebra 7 | using StructArrays 8 | using StaticArrays 9 | 10 | include("mask_utils.jl") 11 | include("spherical_grid_corrections.jl") 12 | 13 | 14 | """ 15 | CartesianGrid2D( dimx, nx, dimy, ny) 16 | 17 | Generate a cartesians mesh on rectangle `dimx`x `dimy` with `nx` x `ny` points 18 | 19 | - `nx` : indices are in [1:nx] 20 | - `ny` : indices are in [1:ny] 21 | - `dimx = xmax - xmin` 22 | - `dimy = ymax - ymin` 23 | - `x, y` : node positions 24 | - `dx, dy` : step size 25 | """ 26 | struct TwoDCartesianGridStatistics <: CartesianGridStatistics 27 | 28 | Nx::BoundaryType 29 | Ny::BoundaryType 30 | Ndx::Int 31 | Ndy::Int 32 | 33 | xmin::Float64 34 | xmax::Float64 35 | ymin::Float64 36 | ymax::Float64 37 | 38 | dimx::Float64 39 | dimy::Float64 40 | 41 | dx::Float64 42 | dy::Float64 43 | 44 | area::Float64 45 | angle_dx::Float64 46 | 47 | function TwoDCartesianGridStatistics(xmin, xmax, Nx::Int, ymin, ymax, Ny::Int; angle=0.0, periodic_boundary::Tuple{Bool, Bool}=(false, false)) 48 | dimx = xmax - xmin 49 | dimy = ymax - ymin 50 | 51 | Ndx = Nx - 1 52 | Ndy = Ny - 1 53 | 54 | dx = dimx / Ndx 55 | dy = dimy / Ndy 56 | 57 | area = dx * dy 58 | 59 | Nx = periodic_boundary[1] ? N_Periodic(Nx) : N_NonPeriodic(Nx) 60 | Ny = periodic_boundary[2] ? N_Periodic(Ny) : N_NonPeriodic(Ny) 61 | 62 | return new(Nx, Ny, Ndx, Ndy, xmin, xmax, ymin, ymax, dimx, dimy, dx, dy, area, angle) 63 | end 64 | end 65 | 66 | 67 | struct TwoDCartesianGridMesh <: CartesianGrid2D 68 | data::StructArray{<:Any} 69 | stats::TwoDCartesianGridStatistics 70 | ProjetionKernel::Function 71 | PropagationCorrection::Function 72 | end 73 | 74 | function TwoDCartesianGridMesh(grid::CartesianGridStatistics; mask=nothing, total_mask=nothing) 75 | 76 | x = collect(range(grid.xmin, stop=grid.xmax, step=grid.dx)) 77 | y = collect(range(grid.ymin, stop=grid.ymax, step=grid.dy)) 78 | 79 | XX = transpose(reshape(repeat(x, inner=length(y)), length(y), length(x))) 80 | YY = transpose(reshape(repeat(y, outer=length(x)), length(y), length(x))) 81 | 82 | if isnothing(mask) 83 | mask = ones(Bool, size(XX))#fill(1, size(XX)) 84 | else 85 | mask = mask 86 | end 87 | 88 | if isnothing(total_mask) 89 | mask = make_boundaries(mask, grid.Nx::BoundaryType, grid.Ny::BoundaryType) 90 | else 91 | mask = total_mask 92 | end 93 | # mask = make_boundaries(mask) 94 | 95 | return StructArray( 96 | x=XX, 97 | y=YY, 98 | mask=mask 99 | ) 100 | 101 | end 102 | 103 | # initalization 104 | function TwoDCartesianGridMesh( xmin, xmax, Nx::Int, ymin, ymax, Ny::Int; mask=nothing, angle=0.0, periodic_boundary = (false, false)) 105 | GS = TwoDCartesianGridStatistics(xmin, xmax, Nx, ymin, ymax, Ny ; angle = angle, periodic_boundary = periodic_boundary) 106 | GMesh = TwoDCartesianGridMesh(GS, mask= mask) 107 | return TwoDCartesianGridMesh(GMesh, GS, ProjetionKernel, SphericalPropagationCorrection_dummy) 108 | end 109 | 110 | # short hand for function above 111 | TwoDCartesianGridMesh(dimx, nx::Int, dimy, ny::Int ; angle=0.0, periodic_boundary = (false, false)) = 112 | TwoDCartesianGridMesh( 0.0, dimx, nx, 0.0, dimy, ny; mask=nothing, angle=angle, periodic_boundary = periodic_boundary) 113 | 114 | 115 | function ProjetionKernel(stats::CartesianGridStatistics) 116 | if stats.angle_dx == 0.0 117 | M = [ 118 | 1/stats.dx 0; 119 | 0 1/stats.dy 120 | ] 121 | else 122 | cosa = cos(stats.angle_dx * pi / 180) 123 | sina = sin(stats.angle_dx * pi / 180) 124 | 125 | M = @SArray [ 126 | cosa/stats.dx sina/stats.dy; 127 | sina/stats.dx cosa/stats.dy 128 | ] 129 | end 130 | return M 131 | end 132 | 133 | # alias for initialization call 134 | ProjetionKernel(Gi::NamedTuple, stats::CartesianGridStatistics) = ProjetionKernel(stats) 135 | # alias for GRid object 136 | ProjetionKernel(G::TwoDCartesianGridMesh) = ProjetionKernel(G.stats) 137 | 138 | 139 | # %% ADD 1D version here 140 | 141 | 142 | 143 | end # module -------------------------------------------------------------------------------- /src/Grids/Grids.jl: -------------------------------------------------------------------------------- 1 | module Grids 2 | 3 | using ...Architectures: AbstractGrid, AbstractGridStatistics, TripolarGrid 4 | 5 | export TripolarGridMOM6 6 | export CartesianGrid 7 | export SphericalGrid 8 | #, TwoDCartesianGridStatistics, TwoDCartesianGridMesh 9 | 10 | include("mask_utils.jl") 11 | include("spherical_grid_corrections.jl") 12 | 13 | include("TripolarGridMOM6.jl") 14 | using .TripolarGridMOM6 15 | 16 | include("CartesianGrid.jl") 17 | using .CartesianGrid 18 | 19 | include("SphericalGrid.jl") 20 | using .SphericalGrid 21 | 22 | 23 | end # module -------------------------------------------------------------------------------- /src/Grids/SphericalGrid.jl: -------------------------------------------------------------------------------- 1 | module SphericalGrid 2 | 3 | using ...Architectures: AbstractGrid, AbstractGridStatistics, CartesianGrid1D, SphericalGrid, CartesianGridStatistics, AbstractBoundary, BoundaryType, SphericalGridStatistics, SphericalGrid2D 4 | using ...custom_structures: N_Periodic, N_NonPeriodic, N_TripolarNorth 5 | 6 | #using LinearAlgebra 7 | using StructArrays 8 | using StaticArrays 9 | 10 | include("mask_utils.jl") 11 | include("spherical_grid_corrections.jl") 12 | 13 | # Generate Spherical mesh statistics on rectangle `dimx`x `dimy` with `nx` x `ny` points 14 | 15 | # - `nx` : indices are in [1:nx] 16 | # - `ny` : indices are in [1:ny] 17 | # - `dimx = xmax - xmin` 18 | # - `dimy = ymax - ymin` 19 | # - `x, y` : node positions 20 | # - `dx, dy` : step size 21 | 22 | 23 | ## Utilites 24 | 25 | function cal_dx_degree(XX) 26 | dx = zeros(size(XX)) 27 | dx[2:end-1, :] = (XX[3:end, :] - XX[1:end-2, :]) / 2 28 | dx[1, :] = (XX[2, :] - XX[1, :]) 29 | dx[end, :] = (XX[end, :] - XX[end-1, :]) 30 | return dx 31 | end 32 | 33 | function cal_dy_degree(YY) 34 | dy = zeros(size(YY)) 35 | dy[:, 2:end-1] = (YY[:, 3:end] - YY[:, 1:end-2]) / 2 36 | dy[:, 1] = (YY[:, 2] - YY[:, 1]) 37 | dy[:, end] = (YY[:, end] - YY[:, end-1]) 38 | return dy 39 | end 40 | 41 | 42 | """ 43 | cal_dx_meters(XX, YY) 44 | 45 | This function calculates the distance in meters between two points on the sphere in the longitude direction. 46 | 47 | # Arguments 48 | - `XX::Array{Float64, 2}`: 2D array of x-coordinates in degrees. 49 | - `YY::Array{Float64, 2}`: 2D array of y-coordinates in degrees. 50 | 51 | # Returns 52 | - `Array{Float64, 2}`: 2D array of distances in meters between points in the longitude direction. 53 | """ 54 | function cal_dx_meters(XX, YY) 55 | 56 | R = 6371.0e3 #meters 57 | R_meridian = R * cos.(YY * pi / 180) #meters 58 | return cal_dx_degree(XX) * pi / 180 .* R_meridian 59 | end 60 | 61 | 62 | """ cal_dy_meters(YY) 63 | 64 | This function calculates the distance in meters between two points on the sphere in the latitude direction. 65 | 66 | # Arguments 67 | - `YY::Array{Float64, 2}`: 2D array of y-coordinates in degrees. 68 | 69 | # Returns 70 | - `Array{Float64, 2}`: 2D array of distances in meters between points in the latitude direction. 71 | """ 72 | function cal_dy_meters(YY) 73 | R = 6371.0e3 #meters 74 | return cal_dy_degree(YY) * pi / 180 .* R 75 | end 76 | 77 | 78 | 79 | """ 80 | TwoDSphericalGridStatistics 81 | 82 | A module for set the statistics on a 2D spherical grid. This module provides variables needed to define the spherical grid. 83 | 84 | inputs 85 | - `xmin` : minimum longitude 86 | - `xmax` : maximum longitude 87 | - `Nx` : number of grid points in the x direction 88 | - `ymin` : minimum latitude 89 | - `ymax` : maximum latitude 90 | - `Ny` : number of grid points in the y direction 91 | - `angle` : angle of rotation of the grid in degrees 92 | - `periodic_boundary` : Tuple{Bool,Bool} = (false, false) - if the grid is periodic in the x and y directions 93 | 94 | # Example 95 | grid =TwoDSphericalGridStatistics(10, 20, 11, 10, 30, 41) 96 | 97 | 98 | """ 99 | struct TwoDSphericalGridStatistics <: SphericalGridStatistics 100 | 101 | Nx::BoundaryType 102 | Ny::BoundaryType 103 | Ndx::Int 104 | Ndy::Int 105 | 106 | xmin::Float64 107 | xmax::Float64 108 | ymin::Float64 109 | ymax::Float64 110 | 111 | dimx::Float64 # size in x 112 | dimy::Float64 # szie in y 113 | 114 | dx_deg::Float64 # resolution in degrees in x 115 | dy_deg::Float64 # resolution in degrees in y 116 | 117 | angle_dx::Float64 118 | 119 | mask_value::Int 120 | 121 | 122 | 123 | function TwoDSphericalGridStatistics(xmin, xmax, Nx::Int, ymin, ymax, Ny::Int; mask_value=1, angle=0.0, periodic_boundary::Tuple{Bool,Bool}=(false, false)) 124 | dimx = xmax - xmin 125 | dimy = ymax - ymin 126 | 127 | Ndx = Nx - 1 128 | Ndy = Ny - 1 129 | 130 | Nx = periodic_boundary[1] ? N_Periodic(Nx) : N_NonPeriodic(Nx) 131 | Ny = periodic_boundary[2] ? N_Periodic(Ny) : N_NonPeriodic(Ny) 132 | 133 | dx_deg = dimx / Ndx 134 | dy_deg = dimy / Ndy 135 | 136 | return new(Nx, Ny, Ndx, Ndy, xmin, xmax, ymin, ymax, dimx, dimy, dx_deg, dy_deg, angle, mask_value) 137 | end 138 | end 139 | 140 | 141 | 142 | # %% 143 | 144 | """ 145 | Module: Grids.SphericalGrid 146 | 147 | inputs: 148 | data: StructArray{<:Any} 149 | stats: TwoDSphericalGridStatistics 150 | ProjetionKernel: Function that returns the projection kernel for the grid 151 | 152 | 153 | # Examples 154 | 155 | """ 156 | struct TwoDSphericalGridMesh <: SphericalGrid2D 157 | data::StructArray{<:Any} 158 | stats::TwoDSphericalGridStatistics 159 | ProjetionKernel::Function 160 | PropagationCorrection::Function 161 | end 162 | 163 | function TwoDSphericalGridMesh(grid::SphericalGridStatistics; mask=nothing, total_mask=nothing) 164 | 165 | x = collect(range(grid.xmin, stop=grid.xmax, step=grid.dx_deg)) 166 | y = collect(range(grid.ymin, stop=grid.ymax, step=grid.dy_deg)) 167 | 168 | XX = transpose(reshape(repeat(x, inner=length(y)), length(y), length(x))) 169 | YY = transpose(reshape(repeat(y, outer=length(x)), length(y), length(x))) 170 | 171 | dx = cal_dx_meters(XX, YY) # meters, centered around grid vertex 172 | dy = cal_dy_meters(YY) # meters, centered around grid vertex 173 | area = dx .* dy # meters^2 174 | 175 | if isnothing(mask) 176 | mask = ones(Bool, size(XX))#fill(1, size(XX)) 177 | else 178 | mask = mask 179 | end 180 | 181 | if isnothing(total_mask) 182 | mask = make_boundaries(mask, grid.Nx::BoundaryType, grid.Ny::BoundaryType) 183 | else 184 | mask = total_mask 185 | end 186 | # mask = make_boundaries(mask) 187 | 188 | return StructArray( 189 | x=XX, 190 | y=YY, 191 | dx=dx, 192 | dy =dy, 193 | area=area, 194 | mask=mask 195 | ) 196 | 197 | end 198 | 199 | # initalization 200 | function TwoDSphericalGridMesh(xmin, xmax, Nx::Int, ymin, ymax, Ny::Int; mask=nothing, angle=0.0, periodic_boundary=(false, false)) 201 | GS = TwoDSphericalGridStatistics(xmin, xmax, Nx, ymin, ymax, Ny; angle=angle, periodic_boundary=periodic_boundary) 202 | GMesh = TwoDSphericalGridMesh(GS, mask=mask) 203 | return TwoDSphericalGridMesh(GMesh, GS, ProjetionKernel, SphericalPropagationCorrection) 204 | end 205 | 206 | ## projection Kernel for this grid: 207 | function ProjetionKernel(Gdata::StructArray) 208 | cos_lat = cos.(Gdata.dy * pi / 180) 209 | # R = 6371.0e3 #meters 210 | 211 | # in normalized degree lon/latitude 212 | #@SArray 213 | # proj(cos_lat, dx, dy, mask, R) = mask == 1 ? SMatrix{2,2}([ 214 | # 180/(R*cos_lat*pi*dx) 0; 215 | # 0 180/(R * pi * dy) 216 | # ]) : nothing 217 | 218 | proj(cos_lat, dx, dy, mask, R) = mask == 1 ? SMatrix{2,2}([ 219 | 1/(cos_lat*dx) 0; 220 | 0 1/(dy) 221 | ]) : nothing 222 | 223 | M = map(proj, cos_lat, Gdata.dx, Gdata.dy, Gdata.mask, R) 224 | return M 225 | end 226 | 227 | 228 | function ProjetionKernel(Gi::NamedTuple, stats::TwoDSphericalGridStatistics) 229 | 230 | cos_lat = cos.(Gi.dy * pi / 180) 231 | # R = 6371.0e3 #meters 232 | 233 | # in normalized degree lon/latitude 234 | return SMatrix{2,2}([ 235 | 1/(cos_lat * Gi.dx) 0; 236 | 0 1/Gi.dy 237 | ]) 238 | end 239 | 240 | 241 | # # alias for GRid object 242 | ProjetionKernel(G::TwoDSphericalGridMesh) = ProjetionKernel(G.stats) 243 | 244 | 245 | end -------------------------------------------------------------------------------- /src/Grids/files/ocean_hgrid_221123.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mochell/PiCLES/ecddc4b2e3564469eb02d607608c0cac06e9dbc4/src/Grids/files/ocean_hgrid_221123.nc -------------------------------------------------------------------------------- /src/Grids/files/ocean_topo_tx2_3v2_240501.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mochell/PiCLES/ecddc4b2e3564469eb02d607608c0cac06e9dbc4/src/Grids/files/ocean_topo_tx2_3v2_240501.nc -------------------------------------------------------------------------------- /src/Grids/mask_utils.jl: -------------------------------------------------------------------------------- 1 | 2 | using ...Architectures: BoundaryType 3 | using Statistics 4 | 5 | """ 6 | interior_boundary(mask::Array{Bool,2}) 7 | function that returns the interior boundary points of the mask 8 | mask == 1: ocean 9 | mask == 0: land 10 | 11 | return bmask: Array{Bool, 2} - mask with interior boundary points == 1, else 0 12 | 13 | """ 14 | function interior_boundary(mask::Union{Array{Bool,2}, BitMatrix}) 15 | # interios boundary points 16 | bmask = zeros(Bool, size(mask)) 17 | for dims in [(1, 0), (-1, 0), (0, 1), (0, -1)] 18 | bmask += circshift(mask, dims) .&& .!mask 19 | end 20 | bmask = bmask .!= 0 21 | return bmask 22 | end 23 | 24 | """ 25 | make_boundaries(mask::Array{Bool, 2}) 26 | function that returns total mask with 27 | - 0: land 28 | - 1: ocean 29 | - 2: land boundary 30 | - 3: grid boundary 31 | 32 | inputs: 33 | mask: Array{Bool, 2} - ocean mask of the grid (1 ocean , 0 land), no Int matrix allowed! 34 | 35 | returns: 36 | total_mask: Array{Int, 2} - mask with ocean, land, land boundary and grid boundary 37 | """ 38 | function make_boundaries(mask::Union{Array{Bool,2},BitMatrix}, Nx::BoundaryType, Ny::BoundaryType) 39 | 40 | bmask = interior_boundary(mask) 41 | 42 | total_mask = mask + 2 * bmask 43 | 44 | if Nx isa N_NonPeriodic 45 | total_mask[1, :] .= 3 46 | total_mask[end, :] .= 3 47 | end 48 | 49 | if Ny isa N_NonPeriodic 50 | total_mask[:, 1] .= 3 51 | total_mask[:, end] .= 3 52 | end 53 | 54 | return total_mask 55 | end 56 | 57 | 58 | """ 59 | make_boundary_lists(total_mask::Array{Int, 2}) 60 | function that returns lists of boundary nodes (tuples of indixes) 61 | 62 | inputs: 63 | total_mask: Array{Int, 2} - mask with ocean, land, land boundary and grid boundary 64 | 65 | returns: 66 | ocean: Vector{CartesianIndex} - ocean indicies 67 | land_boundary: Vector{CartesianIndex} - land boundary indicies 68 | grid_boundary: Vector{CartesianIndex} - grid boundaries indicies 69 | land: Vector{CartesianIndex} - land indicies 70 | """ 71 | function make_boundary_lists(total_mask) 72 | 73 | land_boundary = findall(total_mask .== 2) 74 | grid_boundary = findall(total_mask .== 3) 75 | ocean = findall(total_mask .== 1) 76 | #land = findall(total_mask .== 0) 77 | 78 | return (ocean = ocean, 79 | land_boundary = land_boundary, 80 | grid_boundary = grid_boundary) 81 | #land = land) 82 | end 83 | 84 | 85 | # mutable struct BList 86 | # ocean::Vector{CartesianIndex} 87 | # land_boundary::Vector{CartesianIndex} 88 | # grid_boundary::Vector{CartesianIndex} 89 | # land::Vector{CartesianIndex} 90 | # end 91 | 92 | 93 | 94 | 95 | """ 96 | function mask_circle!(mask, grid, pp_ij , radius) 97 | adds a circular masked area to the existing mask 98 | 99 | mask 1 ocean, 0 is land 100 | grid grid instance 101 | pp)ij i,j position of the center 102 | radius radius in degree 103 | 104 | returns mask with circular masked areas 105 | """ 106 | function mask_circle!(mask, grid, pp_ij, radius) 107 | 108 | #in_circle(xy, pp, r) = (xy[1] - pp[1])^2 + (xy[2] - pp[2])^2 < r^2 109 | 110 | mask_circle!(mask, grid.data.x, grid.data.y, pp_ij, radius) 111 | 112 | # pp = grid.data.x[pp_ij[1], pp_ij[2]], grid.data.y[pp_ij[1], pp_ij[2]] 113 | 114 | # for ij in CartesianIndices(mask) 115 | # x, y = grid.data.x[ij[1], ij[2]], grid.data.y[ij[1], ij[2]] 116 | # # @info x, y, in_circle( (x, y) , pp, 5) 117 | # if in_circle((x, y), pp, radius) 118 | # mask[ij[1], ij[2]] = false 119 | # end 120 | # end 121 | # return mask 122 | end 123 | 124 | 125 | function mask_circle!(mask, xx, yy, pp_ij, radius) 126 | 127 | in_circle(xy, pp, r) = (xy[1] - pp[1])^2 + (xy[2] - pp[2])^2 < r^2 128 | 129 | pp = xx[pp_ij[1], pp_ij[2]], yy[pp_ij[1], pp_ij[2]] 130 | 131 | for ij in CartesianIndices(mask) 132 | x, y = xx[ij[1], ij[2]], yy[ij[1], ij[2]] 133 | # @info x, y, in_circle( (x, y) , pp, 5) 134 | if in_circle((x, y), pp, radius) 135 | mask[ij[1], ij[2]] = false 136 | end 137 | end 138 | # return mask 139 | end -------------------------------------------------------------------------------- /src/Grids/mask_utils_test.jl: -------------------------------------------------------------------------------- 1 | using Pkg 2 | Pkg.activate("PiCLES/") 3 | 4 | using PiCLES.Grids.CartesianGrid: TwoDCartesianGridMesh, ProjetionKernel, TwoDCartesianGridStatistics 5 | using PiCLES.Grids 6 | 7 | 8 | # %% 9 | 10 | grid = TwoDCartesianGridMesh(400e3, 21, 200e3, 11) 11 | 12 | # % Make fake mask 13 | mask = ones(Bool, size(grid.data.x)) # 1 is ocean, 0 is land (?) 14 | mask[10:20, 5:10] .= 0 15 | # mask = .! mask # to make one active block 16 | 17 | # reset mesh with amsk 18 | gridstats_mask = TwoDCartesianGridMesh(grid.stats; mask=mask) 19 | grid = TwoDCartesianGridMesh(gridstats_mask, grid.stats, ProjetionKernel) 20 | 21 | 22 | # %% 23 | mask = grid.data.mask 24 | total_mask = Grids.make_boundaries(mask) 25 | 26 | blists = Grids.make_boundary_lists(total_mask, periodic_boundary=true) 27 | 28 | length(blists.land_boundary) + length(blists.grid_boundary) + length(blists.ocean) + sum(total_mask .== 0) == length(mask) 29 | length(blists.land_boundary) == 30 30 | length(blists.grid_boundary) == 60 31 | 32 | blists = Grids.make_boundary_lists(total_mask, periodic_boundary=false) 33 | 34 | length(blists.land_boundary) + length(blists.ocean) + sum(total_mask .== 0) == length(mask) 35 | length(blists.land_boundary) == 90 36 | length(blists.grid_boundary) == 90 37 | 38 | -------------------------------------------------------------------------------- /src/Grids/spherical_grid_corrections.jl: -------------------------------------------------------------------------------- 1 | using ...Architectures: AbstractGrid, AbstractGridStatistics 2 | 3 | function SphericalPropagationCorrection(phi; R=6.3710E+6) 4 | 5 | """ 6 | Function to correct the change of angle due to the spherical propagation of the wave particle 7 | function GreatCircle_correction(cg_bar) 8 | phi Latitude in degrees 9 | R = 6.3710E+6 # earth Radius iun meters 10 | return (cg_bar * tan(phi)) / R 11 | end 12 | """ 13 | coefficient = (sign.(phi) * min(sign.(phi) * tand.(phi), 60)) / R 14 | #coefficient = tand.(phi) / R 15 | 16 | function GreatCircle_correction(cg_x_bar) 17 | return cg_x_bar * coefficient 18 | end 19 | 20 | return GreatCircle_correction 21 | end 22 | 23 | 24 | function SphericalPropagationCorrection(phi, cg_x_bar; R=6.3710E+6) 25 | 26 | """ 27 | function GreatCircle_correction(cg_x_bar) 28 | phi Latitude in degrees 29 | R = 6.3710E+6 # earth Radius iun meters 30 | return (cg_bar * tan(phi)) / R 31 | end 32 | """ 33 | coefficient = (sign.(phi) * min(sign.(phi) * tand.(phi), 60)) / R 34 | #coefficient = tand.(phi) / R 35 | 36 | function GreatCircle_correction(cg_x_bar) 37 | return cg_x_bar * coefficient 38 | end 39 | 40 | return GreatCircle_correction(cg_x_bar) 41 | end 42 | 43 | 44 | """ 45 | function SphericalPropagationCorrection(ij_mesh, gridstats) 46 | SphericalPropagationCorrection(gridd.data.y) 47 | end 48 | """ 49 | function SphericalPropagationCorrection(ij_mesh::NamedTuple, gridstats::AbstractGridStatistics) 50 | SphericalPropagationCorrection(ij_mesh.y) 51 | end 52 | 53 | 54 | function SphericalPropagationCorrection_dummy(ij_mesh::NamedTuple, gridstats::AbstractGridStatistics) 55 | SphericalPropagationCorrection_dummy = x -> 0.0 56 | return SphericalPropagationCorrection_dummy 57 | end 58 | -------------------------------------------------------------------------------- /src/Models/Models.jl: -------------------------------------------------------------------------------- 1 | module Models 2 | 3 | export WaveGrowthModels1D, WaveGrowthModels2D, reset_boundary! 4 | 5 | include("WaveGrowthModels1D.jl") 6 | include("WaveGrowthModels2D.jl") 7 | 8 | using .WaveGrowthModels1D 9 | using .WaveGrowthModels2D 10 | 11 | end -------------------------------------------------------------------------------- /src/Operators/Operators.jl: -------------------------------------------------------------------------------- 1 | module Operators 2 | 3 | export core_1D, core_2D, custom_structures, mapping_1D, mapping_2D, TimeSteppers 4 | export init_z0_to_State! 5 | using SharedArrays 6 | using StaticArrays 7 | 8 | 9 | #include("custom_structures.jl") 10 | #using .custom_structures 11 | 12 | using ..Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance, StateTypeL1 13 | 14 | #include("custom_structures.jl") 15 | using ..custom_structures: ParticleInstance1D, ParticleInstance2D, MarkedParticleInstance 16 | 17 | #include("../Utils/FetchRelations.jl") 18 | using ..FetchRelations 19 | #include("../ParticleSystems/ParticleSystems.jl") 20 | #using .ParticleSystems 21 | 22 | include("utils.jl") 23 | 24 | include("initialize.jl") 25 | include("core_1D.jl") 26 | include("core_2D.jl") 27 | 28 | include("mapping_1D.jl") 29 | include("mapping_2D.jl") 30 | 31 | include("TimeSteppers.jl") 32 | 33 | #using PiCLES.Utils.FetchRelations 34 | 35 | using .core_1D 36 | using .core_2D 37 | using .mapping_1D 38 | using .mapping_2D 39 | using .TimeSteppers 40 | 41 | end -------------------------------------------------------------------------------- /src/Operators/initialize.jl: -------------------------------------------------------------------------------- 1 | 2 | 3 | #### initialize ##### 4 | 5 | using StaticArrays 6 | 7 | """ sets node state values to S at tuple position ij to zi """ 8 | function init_z0_to_State!(S::SharedMatrix, ij::Int, zi::TT) where {TT<:Union{Vector{Float64},SVector{3,Float64}}} 9 | S[ ij[1], :] = zi 10 | nothing 11 | end 12 | 13 | """ sets node state values to S at tuple position ij to zi """ 14 | function init_z0_to_State!(S::StateTypeL1, ij::II, zi::TT) where {II<:Union{Tuple{Int,Int},CartesianIndex}, TT<:Union{Vector{Float64},SVector{3,Float64}}} 15 | S[ij[1],ij[2], :] = zi 16 | nothing 17 | end 18 | 19 | 20 | """ sets particle state values to S. position is taking from particle """ 21 | function set_u_to_shared!(S::StateTypeL1, PI::ParticleInstance2D) 22 | S[ PI.position_ij[1], PI.position_ij[2] , :] = PI.ODEIntegrator.u 23 | nothing 24 | end 25 | 26 | """ takes node state values and pushes them to particle. position is taken from particle """ 27 | function set_u_to_particle!(S::StateTypeL1, PI::AbstractParticleInstance) 28 | set_u!(PI.ODEIntegrator, Get_u_FromShared(S, PI)) 29 | u_modified!(PI.ODEIntegrator,true) 30 | nothing 31 | end 32 | 33 | -------------------------------------------------------------------------------- /src/Operators/utils.jl: -------------------------------------------------------------------------------- 1 | 2 | ##### Callbacks ###### 3 | 4 | """ 5 | wrap_pos!(xx::Float64, L::Float64) 6 | makes periodic boundary conditions. If position xx exceeds 0 or L it is wrapped around 7 | returns new position and if either or not the wrapping appends (bool) 8 | """ 9 | function wrap_pos!(xx::Float64, L::Float64) 10 | wrap_flag = false 11 | if xx > L 12 | xx = xx - L 13 | wrap_flag = true 14 | elseif xx < 0 15 | xx = xx + L 16 | wrap_flag = true 17 | end 18 | 19 | return xx, wrap_flag 20 | end 21 | 22 | """ 23 | Checks if particle's PI position PI.ODEIntegrator.u[1,2] exceeeds the domain limits Lx, Ly 24 | Lx, LY are global variables 25 | If the PI's postions eceeeds the boundary they warpped around and the ODEIntegrator state is modified. 26 | """ 27 | function periodic_BD_single_PI!(PI::AbstractParticleInstance, Lx::Float64) 28 | 29 | #@printf "PI periodic condition called" 30 | ui = copy(PI.ODEIntegrator.u) 31 | ui[3], wrap_pos_PI1 = wrap_pos!(ui[3], Lx) 32 | #ui[2], wrap_pos_PI2 = wrap_pos!(ui[2], Ly) 33 | 34 | if wrap_pos_PI1 #|| wrap_pos_PI1 35 | #@show wrap_pos_PI1 , wrap_pos_PI2 36 | #@printf "wrap pos PI" 37 | #@show PI.ODEIntegrator.u[1] - ui[1] 38 | #@show PI.ODEIntegrator.u[2] - ui[2] 39 | set_u!(PI.ODEIntegrator, ui) 40 | u_modified!(PI.ODEIntegrator, true) 41 | end 42 | nothing #return PI 43 | end 44 | 45 | # """ 46 | # Checks if 47 | # """ 48 | # @everywhere function periodic_BD_single!(S::SharedMatrix) 49 | # S.u[1], wrap_pos_PI = wrap_pos!(S.u[1], Lx) 50 | # S.u[2], wrap_pos_PI = wrap_pos!(S.u[2], Ly) 51 | # nothing 52 | # end 53 | 54 | """ 55 | return the mean position 56 | """ 57 | function show_pos!(PI) 58 | @show "show current position" PI.position_ij, PI.position_xy / dx, PI.ODEIntegrator.u[3] / dx, PI.ODEIntegrator.u[2] 59 | end 60 | 61 | 62 | """ (debubugging function) returns the domains normalized position of the partivle """ 63 | function show_pos!(integrator, G) 64 | @show (integrator.ODEIntegrator.u[3] .- G.xmin) / grid1d.dx 65 | end 66 | 67 | # the following function are another way to have wrapping boundary conditions. 68 | function periodic_condition_x(u, t, integrator) 69 | u[3] > 0 70 | end 71 | -------------------------------------------------------------------------------- /src/ParticleMesh.jl: -------------------------------------------------------------------------------- 1 | module ParticleMesh 2 | 3 | using ..Architectures: AbstractGrid, AbstractGridStatistics, AbstractODESettings, StandardRegular1D_old, StandardRegular2D_old 4 | 5 | export OneDGrid, OneDGridNotes, TwoDGrid, TwoDGridNotes 6 | 7 | 8 | """ 9 | TwoDGrid( dimx, nx, dimy, ny) 10 | 11 | Generate a cartesians mesh on rectangle `dimx`x `dimy` with `nx` x `ny` points 12 | 13 | - `nx` : indices are in [1:nx] 14 | - `ny` : indices are in [1:ny] 15 | - `dimx = xmax - xmin` 16 | - `dimy = ymax - ymin` 17 | - `x, y` : node positions 18 | - `dx, dy` : step size 19 | """ 20 | struct TwoDGrid <: StandardRegular2D_old 21 | Nx::Int 22 | Ny::Int 23 | Ndx::Int 24 | Ndy::Int 25 | 26 | xmin::Float64 27 | xmax::Float64 28 | ymin::Float64 29 | ymax::Float64 30 | 31 | dimx::Float64 32 | dimy::Float64 33 | 34 | dx::Float64 35 | dy::Float64 36 | 37 | function TwoDGrid(xmin, xmax, Nx::Int, ymin, ymax, Ny::Int) 38 | dimx = xmax - xmin 39 | dimy = ymax - ymin 40 | 41 | Ndx = Nx -1 42 | Ndy = Ny -1 43 | 44 | dx = dimx / Ndx 45 | dy = dimy / Ndy 46 | 47 | return new(Nx, Ny, Ndx, Ndy, xmin, xmax, ymin, ymax, dimx, dimy, dx, dy) 48 | end 49 | end 50 | 51 | """ 52 | TwoDGrid( xmin, xmax, nx, ymin, ymax, ny ) 53 | 54 | Simple structure to store mesh data from 2 dimensions 55 | """ 56 | TwoDGrid(dimx, nx::Int, dimy, ny::Int) = TwoDGrid(0.0, dimx, nx, 0.0, dimy, ny) 57 | 58 | 59 | 60 | struct TwoDGridNotes <: AbstractGridStatistics 61 | Nx::Int 62 | Ny::Int 63 | Ndx::Int 64 | Ndy::Int 65 | 66 | xmin::Float64 67 | xmax::Float64 68 | ymin::Float64 69 | ymax::Float64 70 | 71 | dimx::Float64 72 | dimy::Float64 73 | dx::Float64 74 | dy::Float64 75 | 76 | x::Vector{Float64} 77 | y::Vector{Float64} 78 | 79 | function TwoDGridNotes( gridi::TwoDGrid ) 80 | # x = collect(LinRange(0, gridi.dimx, gridi.Nx)) 81 | # y = collect(LinRange(0, gridi.dimy, gridi.Ny)) 82 | x = collect(range(gridi.xmin, stop = gridi.xmax, step = gridi.dx)) 83 | y = collect(range(gridi.ymin, stop = gridi.ymax, step = gridi.dy)) 84 | 85 | return new(gridi.Nx, gridi.Ny, gridi.Ndx, gridi.Ndy, 86 | gridi.xmin, gridi.xmax, gridi.ymin, gridi.ymax, 87 | gridi.dimx, gridi.dimy, gridi.dx, gridi.dy,x, y) 88 | end 89 | end 90 | 91 | function TwoDGridMesh(grid::TwoDGrid; skip=1) 92 | gn = TwoDGridNotes(grid) 93 | gridmesh = [(i, j) for i in gn.x[1:skip:end], j in gn.y[1:skip:end]] 94 | gridmesh_x = [i for i in gn.x[1:skip:end], j in gn.y[1:skip:end]] 95 | gridmesh_y = [j for i in gn.x[1:skip:end], j in gn.y[1:skip:end]] 96 | return (tuples=gridmesh, x=gridmesh_x, y=gridmesh_y) 97 | end 98 | 99 | 100 | 101 | 102 | struct OneDGrid{I,T<:Number} <: StandardRegular1D_old 103 | Nx::I # number grid points 104 | Ndx::I # number cells 105 | xmin::T 106 | xmax::T 107 | dimx::T 108 | dx::T 109 | #FT = Flaot64 110 | function OneDGrid(xmin, xmax, Nx) 111 | dimx = xmax - xmin 112 | Ndx = Nx -1 113 | dx = dimx / Ndx 114 | IT = typeof(Nx) 115 | FT = typeof(dx) 116 | return new{IT, FT}( Nx, Ndx, xmin, xmax, dimx, dx )#, x) 117 | end 118 | end 119 | 120 | 121 | struct OneDGridNotes{I,FT<:Number} <: AbstractGridStatistics 122 | Nx::I # number grid points 123 | Ndx::I # number of cells 124 | xmin::FT 125 | xmax::FT 126 | dimx::FT 127 | dx::FT 128 | x::Vector{FT} 129 | 130 | function OneDGridNotes(grid::OneDGrid ) 131 | x = collect(LinRange(0, grid.dimx, grid.Nx)) 132 | return new{typeof(grid.Nx), typeof(grid.dx)}(grid.Nx, grid.Ndx, grid.xmin, grid.xmax, grid.dimx, grid.dx, x) 133 | end 134 | end 135 | 136 | export get_x 137 | 138 | """ 139 | get_x( mesh, i ) 140 | 141 | Get position 142 | """ 143 | function get_x(m::OneDGrid, i) 144 | return m.xmin + (i - 1) * m.dx 145 | end 146 | 147 | """ 148 | get_cell_and_offset( mesh, x ) 149 | 150 | Get cell and offset 151 | 152 | We compute the cell indices where the particle is and its relative 153 | normalized position inside the cell 154 | 155 | """ 156 | function get_cell_and_offset(m::OneDGrid, x) 157 | cell = floor(Int64, ((x - m.xmin) / m.Lx) * m.nx) + 1 158 | offset = (x - get_x(m, cell)) / dx 159 | 160 | return cell, offset 161 | end 162 | 163 | end 164 | -------------------------------------------------------------------------------- /src/ParticleSystems/ParticleSystems.jl: -------------------------------------------------------------------------------- 1 | module ParticleSystems 2 | 3 | export particle_waves_v3, particle_waves_v3beta, particle_waves_v4, particle_waves_v5 4 | 5 | # include("particle_waves_v3beta.jl") 6 | # include("particle_waves_v3.jl") 7 | # include("particle_waves_v4.jl") 8 | include("particle_waves_v5.jl") 9 | 10 | # using .particle_waves_v3beta 11 | # using .particle_waves_v3 12 | # using .particle_waves_v4 13 | using .particle_waves_v5 14 | 15 | 16 | end -------------------------------------------------------------------------------- /src/PiCLES.jl: -------------------------------------------------------------------------------- 1 | """ 2 | Main module for 'PiCLES.jl' 3 | """ 4 | module PiCLES 5 | 6 | # external modules 7 | using HDF5 8 | using DocStringExtensions 9 | #using Printf 10 | 11 | export 12 | # run simulation 13 | Simulations, 14 | 15 | #Operators/Core 16 | Operators, 17 | 18 | # models 19 | Models, 20 | 21 | # Particle Systems 22 | ParticleSystems, 23 | 24 | # grids 25 | ParticleMesh, 26 | Grids, 27 | 28 | # utils 29 | Utils, Debugging, FetchRelations, ParticleTools, WindEmulator 30 | 31 | 32 | #externals 33 | 34 | 35 | include("Architectures.jl") 36 | using .Architectures 37 | 38 | include("custom_structures.jl") 39 | 40 | include("ParticleSystems/ParticleSystems.jl") 41 | using .ParticleSystems 42 | 43 | include("FetchRelations.jl") 44 | using .FetchRelations 45 | 46 | include("ParticleMesh.jl") 47 | include("ParticleInCell.jl") 48 | using .ParticleMesh 49 | using .ParticleInCell 50 | 51 | include("Grids/Grids.jl") 52 | using .Grids 53 | 54 | include("Operators/Operators.jl") 55 | include("Simulations/Simulations.jl") 56 | 57 | #include("Grids/Grids.jl") 58 | 59 | #include("Particles/Particles.jl") 60 | 61 | include("Utils/Utils.jl") 62 | using .Utils 63 | 64 | 65 | using .Simulations 66 | 67 | 68 | include("Models/Models.jl") 69 | using .Models 70 | 71 | include("visualization/Plotting.jl") 72 | using .Plotting 73 | 74 | end -------------------------------------------------------------------------------- /src/Simulations/Simulations.jl: -------------------------------------------------------------------------------- 1 | module Simulations 2 | 3 | export Simulation 4 | export StateStore, CashStore, state_store, init_state_store!, push_state_to_storage!, AbstractStore, convert_store_to_tuple 5 | export add_winds_forcing_to_store!, reset_state_store!, show_stored_data, close_store!, EmptyStore, StateStore 6 | export run!, reset_simulation!, initialize_simulation! 7 | export convert_store_to_tuple 8 | 9 | using ..Architectures: AbstractStore 10 | 11 | using SharedArrays 12 | 13 | include("simulation.jl") 14 | include("storing.jl") 15 | include("run.jl") 16 | 17 | 18 | using ..ParticleMesh: OneDGrid, OneDGridNotes 19 | using ..Operators.core_1D: SeedParticle! 20 | using ..Operators.TimeSteppers 21 | 22 | end -------------------------------------------------------------------------------- /src/Simulations/simulation.jl: -------------------------------------------------------------------------------- 1 | 2 | using DataStructures 3 | using Oceananigans: AbstractDiagnostic, AbstractOutputWriter, fields 4 | 5 | import Oceananigans: fields 6 | using Oceananigans.Units 7 | 8 | using ..Architectures: AbstractStore 9 | 10 | #using PiCLES.Architectures: StateOrNothing, StateStore, AbstractStore, EmptyStore 11 | 12 | mutable struct Simulation{ML, TS, DT, ST, DI, OW, CB} 13 | model :: ML 14 | timestepper :: TS 15 | Δt :: DT 16 | stop_iteration :: Float64 17 | stop_time :: ST 18 | wall_time_limit :: Float64 19 | diagnostics :: DI 20 | output_writers :: OW 21 | callbacks :: CB 22 | run_wall_time :: Float64 23 | running :: Bool 24 | initialized :: Bool 25 | verbose :: Bool 26 | store :: AbstractStore 27 | store_itereation :: Int 28 | end 29 | 30 | """ 31 | Simulation(model; Δt, 32 | verbose = true, 33 | stop_iteration = Inf, 34 | stop_time = Inf, 35 | wall_time_limit = Inf) 36 | 37 | Construct a `Simulation` for a `model` with time step `Δt`. 38 | 39 | Keyword arguments 40 | ================= 41 | 42 | - `Δt`: Required keyword argument specifying the simulation time step. Can be a `Number` 43 | for constant time steps or a `TimeStepWizard` for adaptive time-stepping. 44 | 45 | - `stop_iteration`: Stop the simulation after this many iterations. 46 | 47 | - `stop_time`: Stop the simulation once this much model clock time has passed. 48 | 49 | - `wall_time_limit`: Stop the simulation if it's been running for longer than this many 50 | seconds of wall clock time. 51 | """ 52 | function Simulation(model; Δt, 53 | verbose = true, 54 | stop_iteration = Inf, 55 | stop_time = Inf, 56 | wall_time_limit = Inf) 57 | 58 | if stop_iteration == Inf && stop_time == Inf && wall_time_limit == Inf 59 | @warn "This simulation will run forever as stop iteration = stop time " * 60 | "= wall time limit = Inf." 61 | end 62 | 63 | diagnostics = OrderedDict{Symbol, AbstractDiagnostic}() 64 | output_writers = OrderedDict{Symbol, AbstractOutputWriter}() 65 | #callbacks = OrderedDict{Symbol, Callback}() 66 | 67 | # callbacks[:stop_time_exceeded] = Callback(stop_time_exceeded) 68 | # callbacks[:stop_iteration_exceeded] = Callback(stop_iteration_exceeded) 69 | # callbacks[:wall_time_limit_exceeded] = Callback(wall_time_limit_exceeded) 70 | 71 | # Check for NaNs in the model's first prognostic field every 100 iterations. 72 | model_fields = fields(model) 73 | field_to_check_nans = NamedTuple{keys(model_fields) |> first |> tuple}(first(model_fields) |> tuple) 74 | #nan_checker = NaNChecker(field_to_check_nans) 75 | #callbacks[:nan_checker] = Callback(nan_checker, IterationInterval(100)) 76 | 77 | # Convert numbers to floating point; otherwise preserve type (eg for DateTime types) 78 | FT = Float64 #eltype(model.grid) 79 | Δt = Δt isa Number ? FT(Δt) : Δt 80 | stop_time = stop_time isa Number ? FT(stop_time) : stop_time 81 | 82 | store = EmptyStore(1) 83 | 84 | return Simulation(model, 85 | model.timestepper, 86 | Δt, 87 | Float64(stop_iteration), 88 | stop_time, 89 | Float64(wall_time_limit), 90 | diagnostics, 91 | output_writers, 92 | nothing, #callbacks, 93 | 0.0, 94 | false, 95 | false, 96 | verbose, 97 | store, 98 | 0) 99 | end 100 | 101 | 102 | #fields(model::WaveGrowth) = (State = model.State, ) 103 | -------------------------------------------------------------------------------- /src/Simulations/storing.jl: -------------------------------------------------------------------------------- 1 | using HDF5 2 | using DataStructures 3 | 4 | using ..ParticleMesh 5 | #using Simulation 6 | 7 | struct EmptyStore{Int} <: AbstractStore 8 | iteration::Int 9 | end 10 | 11 | 12 | 13 | mutable struct CashStore{HDFg,Int} <: AbstractStore 14 | store::HDFg 15 | iteration::Int 16 | end 17 | 18 | 19 | 20 | mutable struct StateStore{FL,HDFg,Int,ST} <: AbstractStore 21 | file::FL 22 | store::HDFg 23 | iteration::Int 24 | shape::ST 25 | end 26 | 27 | const StateOrNothing = Union{AbstractStore,Nothing} 28 | 29 | """ 30 | state_store(path, coords; name="state", replace=true, mode="w") 31 | Initializes the state store at `path` with the given `coords`. 32 | coords are the coordinates of the state store, e.g. (time, x, y, z), with time being the first dimension. 33 | name is the name of the state store, e.g. "state" 34 | replace is a boolean, if true, the state store is replaced, if false, the state store is appended to (not tested yet). 35 | """ 36 | function state_store(path, coords; name="state", replace=true, mode="w") 37 | 38 | if replace 39 | rm(joinpath(path, name * ".h5"), force=true) 40 | end 41 | 42 | file = h5open(joinpath(path, name * ".h5"), "w") 43 | 44 | shape = Tuple(Int(x) for x in [length(x) for x in coords]) 45 | 46 | store_waves = create_group(file, "waves") 47 | store_waves_data = create_dataset( 48 | store_waves, "data", Float64, 49 | (shape) 50 | )#, chunk=(2,)) 51 | 52 | dim_names = [String(x) for x in keys(coords)] 53 | write_attribute(store_waves, "dims", dim_names) 54 | for (k, v) in zip(keys(coords), coords) 55 | #println(k, " => ", v) 56 | store_waves[String(k)] = v 57 | end 58 | store_waves["var_names"] = ["e", "m_x", "m_y"] 59 | 60 | 61 | return StateStore(file, store_waves, 1, shape) 62 | end 63 | 64 | 65 | function make_coords(grid::TwoDGrid) 66 | x = collect(LinRange(0, grid.dimx, grid.Nx)) 67 | y = collect(LinRange(0, grid.dimy, grid.Ny)) 68 | (x=x, y=y) 69 | end 70 | 71 | function make_coords(grid::OneDGrid) 72 | x = collect(LinRange(0, grid.dimx, grid.Nx)) 73 | (x=x,) 74 | end 75 | 76 | 77 | """ 78 | init_state_store!(sim, save_path; state= ["e", "m_x", "m_y"], kwargs... , ) 79 | Initializes the state store for the simulation sim. 80 | save_path is the path where the state store is saved. 81 | state is a vector of strings, which are the names of the state variables to be stored. 82 | """ 83 | function init_state_store!(sim, save_path; state=["e", "m_x", "m_y"], kwargs...) 84 | 85 | grid = sim.model.grid 86 | coords = make_coords(grid) 87 | #x = collect(LinRange(0, grid.dimx, grid.Nx)) 88 | time_range = range(0.0, sim.stop_time + sim.Δt, step=sim.Δt) 89 | 90 | coords = (; time=Array(time_range), coords..., state=state) 91 | #coords = (time=Array(time_range), x=x, state=state) 92 | 93 | if sim.verbose 94 | @info "init state store" 95 | @info "save path: ", save_path 96 | @info "coords: ", keys(coords) 97 | @info "push state store to sim" 98 | end 99 | setfield!(sim, :store, state_store(save_path, coords; kwargs...)) 100 | 101 | nothing 102 | end 103 | 104 | """ 105 | push_state_to_storage!(sim; i=nothing) 106 | Pushes the current state of the simulation sim to the state store. 107 | i is the iteration number, if nothing, the current iteration number is used. 108 | """ 109 | function push_state_to_storage!(sim; i=nothing) 110 | ii = isnothing(i) ? sim.store.iteration : i 111 | if length(sim.store.shape) == 4 112 | sim.store.store["data"][ii, :, :, :] = sim.model.State 113 | elseif length(sim.store.shape) == 3 114 | sim.store.store["data"][ii, :, :] = sim.model.State 115 | else 116 | error("wrong shape") 117 | end 118 | nothing 119 | end 120 | 121 | 122 | """ 123 | reset_state_store!(sim; value=0.0) 124 | Resets the state store to the given value. 125 | value is to which the state store is reset (default = 0.0). 126 | """ 127 | function reset_state_store!(sim; value::Float64=0.0) 128 | sim.store.store["data"][:, :, :] .= value 129 | reset_store_counter(sim.store) 130 | nothing 131 | end 132 | 133 | 134 | """ 135 | add_winds_forcing_to_store!(store, forcing, coords) 136 | 137 | add winds forcing to store 138 | store is a store object simulation.store 139 | forcing is a tuple of forcing fields 140 | coords is a tuple of coordinates for the forcing fields 141 | """ 142 | function add_winds_forcing_to_store!(store, forcing, coords) 143 | 144 | if ~haskey(store.file, "forcing") 145 | store_winds = create_group(store.file, "forcing") 146 | else 147 | store_winds = store.file["forcing"] 148 | end 149 | 150 | for (name, f) in zip(keys(forcing), forcing) 151 | # test if f is nothing 152 | if f == nothing 153 | continue 154 | else 155 | #print(name, f) 156 | if ~haskey(store_winds, string(name)) 157 | store_i = create_dataset(store_winds, string(name), Float64, size(f))#, chunk=(2,)) 158 | else 159 | store_i = f 160 | end 161 | end 162 | end 163 | 164 | # add coodinates 165 | shape = Tuple(Int(x) for x in [length(x) for x in coords]) 166 | dim_names = [String(x) for x in keys(coords)] 167 | 168 | if ~haskey(attributes(store_winds), "dims") 169 | 170 | print("write dims") 171 | write_attribute(store_winds, "dims", dim_names) 172 | for (k, v) in zip(keys(coords), coords) 173 | println(k, " => ", v) 174 | store_winds[String(k)] = Array(v) 175 | end 176 | 177 | end 178 | 179 | 180 | end 181 | 182 | 183 | function show_stored_data(sim) 184 | print("store has the following keys ", HDF5.keys(sim.store.file), "\n") 185 | sim.store.file 186 | end 187 | 188 | function close_store!(store::AbstractStore) 189 | close(store.file) 190 | end 191 | 192 | function close_store!(sim) 193 | close_store!(sim.store) 194 | end 195 | 196 | 197 | function reset_store_counter(store::EmptyStore) 198 | nothing 199 | end 200 | 201 | function reset_store_counter(store::StateStore) 202 | store.iteration = 1 203 | end 204 | 205 | # -------------- converting rountines ---------- 206 | 207 | """ 208 | convert_store_to_tuple(store::CashStore) 209 | creates a NamedTuple with the data, x, and time from the CashStore 210 | """ 211 | function convert_store_to_tuple(store::CashStore, sim) 212 | store_data = cat(store.store..., dims=3) 213 | store_waves_data = permutedims(store_data, (3, 1, 2)) 214 | wave_x = OneDGridNotes(sim.model.grid).x 215 | wave_time = collect(range(0, sim.stop_time + sim.Δt, length=length(store_waves_data[:, 1, 3]))) 216 | return (data=store_waves_data, x=wave_x, time=wave_time) 217 | end 218 | 219 | 220 | """ 221 | convert_store_to_tuple(store::StateStore) 222 | creates a NamedTuple with the data, x, and time from the StateStore 223 | """ 224 | function convert_store_to_tuple(store::StateStore, sim) 225 | store_waves_data = Array(store.store["data"]) 226 | wave_x = store.store["x"][:] 227 | wave_time = store.store["time"][:] 228 | return (data=store_waves_data, x=wave_x, time=wave_time) 229 | end 230 | -------------------------------------------------------------------------------- /src/Utils/Debugging.jl: -------------------------------------------------------------------------------- 1 | module Debugging 2 | 3 | 4 | 5 | ###### Debugging functions ############ 6 | 7 | """ 8 | ResetParticle!(integrator) 9 | (debubugging function) 10 | Resets the integrator instance if the particle energy is nan or very high 11 | resets the particles position to the domain center 12 | resets the energy to a dfault value (e_min_log is a global variable) 13 | """ 14 | function ResetParticle!(integrator) 15 | if isnan(integrator.ODEIntegrator.u[1]) || exp(integrator.ODEIntegrator.u[1]) >= 1e-3 16 | @show exp(integrator.ODEIntegrator.u[1]) 17 | integrator.ODEIntegrator.u[3] = integrator.ODEIntegrator.u[3] - Lx/2 18 | #integrator.ODEIntegrator.u[2] = integrator.ODEIntegrator.u[2] - Ly/2 19 | #integrator.ODEIntegrator.u[4] = 1e-2 20 | integrator.ODEIntegrator.u[1] = e_min_log 21 | u_modified!(integrator.ODEIntegrator,true) 22 | @show "rest particle" 23 | end 24 | nothing 25 | end 26 | 27 | Lx_terminate_limit = 1 28 | 29 | 30 | """ 31 | TerminateCheckSingle!(integrator) 32 | (debubugging function) 33 | 34 | """ 35 | function TerminateCheckSingle!(integrator) 36 | if maximum(integrator.ODEIntegrator.u[3]) - Lx * Lx_terminate_limit >= 0 #|| maximum(exp.(integrator.u[3:N_state:end]) / e_min_log ) >= 5 37 | terminate!(integrator.ODEIntegrator) 38 | @show "terminate" 39 | end 40 | end 41 | 42 | 43 | 44 | end 45 | -------------------------------------------------------------------------------- /src/Utils/Initialization.jl: -------------------------------------------------------------------------------- 1 | 2 | 3 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 4 | import PiCLES: FetchRelations 5 | using PiCLES.Operators.core_2D: ParticleDefaults 6 | 7 | """ 8 | function Init_Standard(uscale, vscale, DT; r_g0=0.85) 9 | 10 | returns ParticleState, default_ODE_parameters, WindSeamin, Const_ID 11 | """ 12 | function Init_Standard(uscale, vscale, DT; r_g0=0.85) 13 | 14 | Const_ID = PW.get_I_D_constant() 15 | #@set Const_ID.γ = 0.88 16 | Const_Scg = PW.get_Scg_constants() 17 | 18 | default_ODE_parameters = ( 19 | r_g=r_g0, 20 | C_α=Const_Scg.C_alpha, 21 | C_φ=Const_ID.c_β, 22 | C_e=Const_ID.C_e, 23 | g=9.81, 24 | ) 25 | 26 | WindSeamin = FetchRelations.get_initial_windsea(uscale, vscale, DT / 2) 27 | ParticleState = ParticleDefaults(log(WindSeamin["E"]), WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0) 28 | 29 | return ParticleState, default_ODE_parameters, WindSeamin, Const_ID 30 | 31 | end 32 | -------------------------------------------------------------------------------- /src/Utils/InputOutput.jl: -------------------------------------------------------------------------------- 1 | module InputOutput 2 | 3 | using ArgParse 4 | 5 | export parse_args 6 | export Argsettings 7 | 8 | #https://argparsejl.readthedocs.io/en/latest/argparse.html 9 | Argsettings = ArgParseSettings() 10 | @add_arg_table! Argsettings begin 11 | "--ID" 12 | help = "ID (or folder) of make -f run_model.make make_collection the model output" 13 | arg_type = String 14 | "--T" 15 | help = "run time in hours" 16 | arg_type = Float16 17 | "--DT" 18 | help = "re-meshing time step in minutes" 19 | arg_type = Float16 20 | 21 | "--Lx" 22 | help = "domain length in km" 23 | arg_type = Float16 24 | "--Nx" 25 | help = "# of Nodes" 26 | arg_type = Int 27 | 28 | "--U10" 29 | help = "10-meter windspeed amplitude" 30 | arg_type = Float16 31 | 32 | "--c_beta" 33 | help = "grow parameters in 1e-2" 34 | arg_type = Float16 35 | default = Float16(4.0) 36 | "--gamma" 37 | help = "input dissipation coefficient" 38 | arg_type = Float16 39 | "--r_g0" 40 | help = "input dissipation coefficient" 41 | arg_type = Float16 42 | "--periodic" 43 | help = "flag for periodic boundary condition" 44 | arg_type = Bool 45 | action = :store_true 46 | "--parset" 47 | help = "set, or group of experiments" 48 | arg_type = String 49 | # "Name" 50 | # help = "Name of the experiment. if not defined the name is generated" 51 | # arg_type = String 52 | end 53 | 54 | 55 | 56 | 57 | end 58 | -------------------------------------------------------------------------------- /src/Utils/Utils.jl: -------------------------------------------------------------------------------- 1 | module Utils 2 | 3 | export WindEmulator, ParticleTools, Debugging, InputOutput, convert_particles, convert_particles_1D 4 | export Init_Standard 5 | 6 | #include("FetchRelations.jl") 7 | include("WindEmulator.jl") 8 | include("ParticleTools.jl") 9 | include("Debugging.jl") 10 | include("InputOutput.jl") 11 | #include("convert_particles.jl") 12 | #include("convert_particles_1D.jl") 13 | include("Initialization.jl") 14 | 15 | #using .FetchRelations 16 | using .WindEmulator 17 | using .ParticleTools 18 | using .Debugging 19 | using .InputOutput 20 | #using .convert_particles 21 | #using .convert_particles_1D 22 | #using .Initialization 23 | 24 | end -------------------------------------------------------------------------------- /src/Utils/WindEmulator.jl: -------------------------------------------------------------------------------- 1 | module WindEmulator 2 | 3 | export WindEmulationFunction, IdealizedWindGrid, wind_interpolator 4 | export slopped_blob, contant_winds 5 | 6 | using Interpolations 7 | 8 | function IdealizedWindGrid(u_func::Function, dims::NamedTuple, steps::NamedTuple) 9 | 10 | xi = range(0, dims.Lx, step=steps.dx) 11 | ti = range(0, dims.T, step=steps.dt) 12 | 13 | u_func_gridded = [ u_func(xii, tii) for xii in xi, tii in ti] 14 | return (u= u_func_gridded, x=xi, t=ti) 15 | end 16 | 17 | 18 | function wind_interpolator(wind_grid) 19 | if haskey(wind_grid, :y) 20 | nodes = (wind_grid.x, wind_grid.y, wind_grid.t) 21 | else 22 | nodes = (wind_grid.x, wind_grid.t) 23 | end 24 | 25 | if haskey(wind_grid, :u) 26 | u_grid = linear_interpolation( nodes , wind_grid.u ,extrapolation_bc=Periodic()) 27 | #u_grid = CubicSplineInterpolation( (xi, ti), u_func_gridded; bc=Line(OnGrid()), extrapolation_bc=Flat()) 28 | #u_grid = interpolate((xi, ti), u_func_gridded, Gridded(Linear())) 29 | else 30 | u_grid = nothing 31 | end 32 | 33 | if haskey(wind_grid, :v) 34 | v_grid = linear_interpolation( nodes , wind_grid.v ,extrapolation_bc=Periodic()) 35 | else 36 | v_grid = nothing 37 | end 38 | 39 | 40 | tcol= (u=u_grid, v= v_grid) 41 | # Create a new NamedTuple without the entries that are nothing 42 | return (; [p for p in pairs(tcol) if ~isnothing(p[2])]...) 43 | end 44 | 45 | 46 | 47 | 48 | abstract type WindEmulationFunction2 <: Function end 49 | 50 | function slopped_blob(x, t, U10, V, T , x_scale, t_scale; x0=300e3)# <: WindEmulationFunction 51 | return 0.5+ U10 * ( exp(- ( ( x - (x0 + t * V) )./x_scale).^2) .* exp(- ( ( t- (T/2) )./ t_scale ).^2) )#.+ 3 * sin.(x *π/Ly/0.5 .+ y *π/Ly/0.5) 52 | end 53 | 54 | 55 | function contant_winds(x, t, U10)# <: WindEmulationFunction 56 | return x.*0+U10 + t *0 57 | end 58 | 59 | 60 | #u_func(x, t) = 3 * exp(- ( ( x-25e3 + 20e3* t/T )./10e3).^2) #.+ 3 #.+ 3 * sin.(x *π/Ly/0.5 .+ y *π/Ly/0.5) 61 | #u_func(x, t) = 3 * exp(- ( ( x-25e3 )./10e3).^2) .+ t *0 #.+ 3 #.+ 3 * sin.(x *π/Ly/0.5 62 | 63 | #u_func(x, y, t) = y *0 .- x .*2/50e3 .+ 3 #.+ 3 * sin.(x *π/Ly/0.5 .+ y *π/Ly/0.5) 64 | #u_func(x, y, t) = y *0 .- x .*0 .+ 3 #.+ 3 * sin.(x *π/Ly/0.5 .+ y *π/Ly/0.5) 65 | #u_func(x, t) = x *0 .+ IfElse.ifelse.( x .< Lx*2.0/3.0, 3, 0.1) 66 | 67 | # u_func(x, y, t) = y *0 .+ IfElse.ifelse.( x .< Lx/2.0, 68 | # 2 .+ 1, *sin.(x *π/Lx/2), 69 | # 0 .* x + 0.1 70 | # ) 71 | 72 | 73 | 74 | end -------------------------------------------------------------------------------- /src/Utils/convert_particles.jl: -------------------------------------------------------------------------------- 1 | using HDF5 2 | using JLD2 3 | using DataFrames 4 | 5 | import Base: filter! 6 | using DifferentialEquations, Statistics 7 | 8 | 9 | mutable struct ParticleInstance 10 | position_ij :: Tuple 11 | position_xy :: Tuple 12 | ODEIntegrator::OrdinaryDiffEq.ODEIntegrator 13 | 14 | end 15 | 16 | save_path = "data/first_try/" 17 | 18 | ParticleCollection = load_object( joinpath(save_path , "particles.jld2") ) 19 | 20 | 21 | function filter!(mask::BitArray, x::AbstractVector) 22 | pos = findall(x -> x == 0, mask) 23 | [deleteat!(x, p) for p in pos] 24 | end 25 | 26 | function CreateIterationMask(time) 27 | mask = BitArray([z < 0 for z in diff(time)]) 28 | #breaks = findall(x->x==1, mask) 29 | lower_bound = insert!(findall(x->x==1, mask), 1, 0) 30 | lower_bound .+= 1 31 | upper_bound = insert!(findall(x->x==1, mask), length(findall(x->x==1, mask))+1 , length(time)) 32 | time_mask = time * 0 33 | for (i1, i2, timem) in zip(lower_bound, upper_bound, range(1,length(upper_bound), step=1)) 34 | #@show i1, i2, time[i1:i2], ParticleData[i1:i2, :] 35 | time_mask[i1:i2] .= timem 36 | end 37 | return time_mask 38 | end 39 | 40 | DD = [] 41 | for a_particle in ParticleCollection 42 | 43 | D = DataFrame(Tables.columntable(a_particle.ODEIntegrator.sol)) 44 | D.mask = CreateIterationMask(D[!, "timestamp"]) 45 | push!(DD, D[!, [1, 9, 2, 3, 4, 5, 6, 7, 8]] ) 46 | 47 | end 48 | 49 | # %% 50 | @show "save data" 51 | #using HDF5 52 | 53 | mkpath(save_path) 54 | rm(joinpath(save_path , "particle_tables.h5"), force=true) 55 | file = h5open( joinpath(save_path , "particle_tables.h5") , "w" ) 56 | 57 | Np = size(DD)[1] 58 | Ns, Nvar = size(DD[1]) 59 | 60 | store_waves = create_group(file, "particles") 61 | store_waves_data = create_dataset(store_waves, "data", Float64, ( (Np), (Ns), (Nvar) ) )#, chunk=(2,)) 62 | 63 | for i in 1:length(DD) 64 | store_waves_data[i,:,:] = Array(DD[i]) 65 | end 66 | 67 | write_attribute(store_waves, "var_names", names(DD[1]) ) 68 | close(file) 69 | -------------------------------------------------------------------------------- /src/Utils/convert_particles_1D.jl: -------------------------------------------------------------------------------- 1 | using HDF5 2 | using JLD2 3 | using DataFrames 4 | using Printf 5 | 6 | import Base: filter! 7 | using DifferentialEquations, Statistics 8 | 9 | # %% IO - fine the right path and read input arguments 10 | 11 | using InputOutput: Argsettings, parse_args 12 | 13 | #https://argparsejl.readthedocs.io/en/latest/argparse.html 14 | parset = "1D_static/" 15 | 16 | arg_test = ["--ID", "dx1655_dt2400", "--parset", "1D_static"] 17 | passed_argument = parse_args(arg_test, Argsettings) 18 | @unpack ID, parset = passed_argument 19 | 20 | #save_path = joinpath( "data/1D_static/", parsed_args["ID"] ) 21 | save_path = save_path_base*parset*"/"*ID*"/" 22 | 23 | # %% 24 | 25 | 26 | 27 | mutable struct ParticleInstance 28 | position_ij :: Tuple 29 | position_xy :: Tuple 30 | ODEIntegrator::OrdinaryDiffEq.ODEIntegrator 31 | end 32 | 33 | 34 | ParticleCollection = load_object( joinpath(save_path , "particles.jld2") ) 35 | 36 | 37 | function filter!(mask::BitArray, x::AbstractVector) 38 | pos = findall(x -> x == 0, mask) 39 | [deleteat!(x, p) for p in pos] 40 | end 41 | 42 | function CreateIterationMask(time) 43 | mask = BitArray([z < 0 for z in diff(time)]) 44 | #breaks = findall(x->x==1, mask) 45 | lower_bound = insert!(findall(x->x==1, mask), 1, 0) 46 | lower_bound .+= 1 47 | upper_bound = insert!(findall(x->x==1, mask), length(findall(x->x==1, mask))+1 , length(time)) 48 | time_mask = time * 0 49 | for (i1, i2, timem) in zip(lower_bound, upper_bound, range(1,length(upper_bound), step=1)) 50 | #@show i1, i2, time[i1:i2], ParticleData[i1:i2, :] 51 | time_mask[i1:i2] .= timem 52 | end 53 | return time_mask 54 | end 55 | # %% 56 | DD = [] 57 | for a_particle in ParticleCollection 58 | 59 | D = DataFrame(Tables.columntable(a_particle.ODEIntegrator.sol)) 60 | D.mask = CreateIterationMask(D[!, "timestamp"]) 61 | push!(DD, D[!, [1, 2, 3, 4]] ) # time, x(t), c_x(t), lne(t) 62 | 63 | end 64 | 65 | 66 | # %% 67 | @show "save data" 68 | #using HDF5 69 | 70 | mkpath(save_path) 71 | rm(joinpath(save_path , "particle_tables.h5"), force=true) 72 | file = h5open( joinpath(save_path , "particle_tables.h5") , "w" ) 73 | 74 | Np = size(DD)[1] 75 | Ns, Nvar = size(DD[1]) 76 | 77 | store_waves = create_group(file, "particles") 78 | #store_waves_data = create_dataset(store_waves, "data", Float64, ( (Np), (Nvar) ) )#, chunk=(2,)) 79 | 80 | # determine maximu length 81 | Ns_lengths = [] 82 | for i in 1:length(DD) 83 | push!(Ns_lengths, size(Array(DD[i]))[1] ) 84 | end 85 | Ns = maximum(Ns_lengths) 86 | 87 | store_particle = create_dataset(store_waves, "data" , Float64, ( (Np), (Ns), (Nvar) ) )#, chunk=(2,)) 88 | @show (Np), (Ns), (Nvar) 89 | 90 | for i in 1:length(DD) 91 | Ns_i = size(DD[i])[1] 92 | if Ns_i == Ns 93 | store_particle[i, :,:] = Array(DD[i]) 94 | elseif Ns_i < Ns 95 | @show Ns_i, Ns 96 | store_particle[i, 1:Ns_i,:] = Array(DD[i]) 97 | end 98 | end 99 | 100 | write_attribute(store_waves, "var_names", names(DD[1]) ) 101 | close(file) 102 | 103 | # %% 104 | 105 | # # version for separated arrays 106 | # @show (Np), (Ns), (Nvar) 107 | # for i in 1:length(DD) 108 | # Ns, Nvar = size(DD[i]) 109 | # particle_name = string(i, base = 5,pad= 5) 110 | # store_particle = create_dataset(store_waves,particle_name , Float64, ( (Ns), (Nvar) ) )#, chunk=(2,)) 111 | # @show size(Array(DD[i])) 112 | # store_particle[:,:] = Array(DD[i]) 113 | # end 114 | -------------------------------------------------------------------------------- /src/custom_structures.jl: -------------------------------------------------------------------------------- 1 | module custom_structures 2 | 3 | export ParticleInstance1D, ParticleInstance2D, MarkedParticleInstance, AbstractParticleInstance, AbstractMarkedParticleInstance, wni 4 | 5 | using DifferentialEquations: OrdinaryDiffEq.ODEIntegrator 6 | using DocStringExtensions 7 | using StaticArrays 8 | 9 | using ..Architectures: AbstractParticleInstance, AbstractMarkedParticleInstance 10 | using ..Architectures: AbstractBoundary 11 | 12 | # ParticleInstance is the Stucture that carries each particle. 13 | mutable struct ParticleInstance2D <: AbstractParticleInstance 14 | position_ij::Tuple{Int, Int} 15 | position_xy::Tuple{Float64, Float64} 16 | ODEIntegrator::Union{ODEIntegrator,Nothing} 17 | boundary :: Bool 18 | on::Bool 19 | end 20 | 21 | mutable struct ParticleInstance1D <: AbstractParticleInstance 22 | position_ij::Int 23 | position_xy::Float64 24 | ODEIntegrator::ODEIntegrator 25 | boundary::Bool 26 | on::Bool 27 | end 28 | 29 | # Debugging ParticleInstance 30 | mutable struct MarkedParticleInstance <: AbstractMarkedParticleInstance 31 | Particle::AbstractParticleInstance 32 | time :: Float64 33 | state :: Vector{Any} 34 | errorReturnCode 35 | end 36 | 37 | Base.copy(s::ParticleInstance1D) = ParticleInstance1D(s.position_ij, s.position_xy, s.ODEIntegrator, s.boundary, s.on) 38 | Base.copy(s::ParticleInstance2D) = ParticleInstance2D(s.position_ij, s.position_xy, s.ODEIntegrator, s.boundary, s.on) 39 | 40 | # Regridding types: 41 | """Weights & Index (wni) FieldVector """ 42 | struct wni{TI<:SVector,TF<:SVector} <: FieldVector{4,SVector} 43 | xi::TI 44 | xw::TF 45 | yi::TI 46 | yw::TF 47 | end 48 | 49 | # Define Boundary Types: 50 | 51 | struct N_Periodic{T} <: AbstractBoundary 52 | N::T 53 | end 54 | 55 | struct N_NonPeriodic{T} <: AbstractBoundary 56 | N::T 57 | end 58 | 59 | struct N_TripolarNorth{T} <: AbstractBoundary 60 | N::T 61 | end 62 | 63 | # struct N_TripolarSouth{T} <: AbstractBoundary 64 | # N::T 65 | # end 66 | 67 | 68 | 69 | end -------------------------------------------------------------------------------- /src/old_structure/run_collections.jl: -------------------------------------------------------------------------------- 1 | using Printf 2 | 3 | 4 | # using Distributed 5 | # addprocs(2) 6 | # advance_workers = WorkerPool([2, 3]) 7 | 8 | push!(LOAD_PATH, joinpath(pwd(), "code/") ) 9 | # %% 10 | 11 | function make_str(name::String, value::Number) 12 | return name*@sprintf("%i",value) 13 | end 14 | 15 | 16 | function make_str(name::String, value::Number, digits::Number) 17 | return name*@sprintf("%0.2f",round(value, digits= digits) ) 18 | end 19 | 20 | 21 | function concat_str(alist) 22 | str_list ="" 23 | for ai in alist 24 | str_list *= ai * "_" 25 | end 26 | return str_list[1:end-1] 27 | end 28 | 29 | 30 | function concat_str_space(alist) 31 | str_list ="" 32 | for ai in alist 33 | str_list *= ai * " " 34 | end 35 | return str_list[1:end-1] 36 | end 37 | 38 | make_str 39 | 40 | # %% 41 | 42 | # parset_name = "U10-DT" 43 | # #var1_list = [1, 3, 5, 8, 10, 13, 15, 20] 44 | # var1_list = [20] 45 | # var2_list = [3, 5, 8, 10, 15, 20, 30, 40, 60] 46 | # var3_list = [50]#10, 20, 20] 47 | # periodic = false 48 | 49 | # parset_name = "U10-DT-periodic" 50 | # var1_list = [1, 3, 5, 8, 10, 13, 15, 18, 20, 25] # U10 51 | # var2_list = [3, 5, 8, 10, 15, 20, 30, 40, 60] # dt 52 | # var3_list = [40]#10, 20, 20] # NZ 53 | # periodic = true 54 | 55 | parset_name = "U10-DT" 56 | var1_list = [1, 3, 5, 8, 10, 13, 15, 18, 20, 25] # U10 57 | var2_list = [3, 5, 8, 10, 15, 20, 30, 40, 45, 50, 60] # dt 58 | var3_list = [40]#10, 20, 20] # NZ 59 | periodic = false 60 | 61 | # parset_name = "Nx-DT" 62 | # var1_list = [10] 63 | # var2_list = [3, 5, 10, 15, 20, 30, 60] 64 | # var3_list = [5, 8, 10, 20, 30, 40, 50, 80] 65 | # periodic = false 66 | 67 | 68 | # parset_name = "Nx-DT-periodic" 69 | # var1_list = [10] 70 | # var2_list = [3, 5, 10, 15, 20, 30, 60] 71 | # var3_list = [5, 8, 10, 20, 30, 40, 50, 80] 72 | # periodic = true 73 | 74 | # parset_name = "gamma-c_beta" 75 | # var1_list = round.(range(0.88* 0.2 , 0.88* 1.5; length= 10), digits= 2) # gamma 76 | # var2_list = [2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6] # c_beta_parameter 77 | # var3_list = [40]#10, 20, 20] # Nx 78 | # periodic = false 79 | 80 | # 81 | # parset_name = "gamma-c_beta-rg0.85" 82 | # var1_list = round.(range(0.88* 0.2 , 0.88* 1.5; length= 10), digits= 2) # gamma 83 | # var2_list = [2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6] # c_beta_parameter 84 | # var3_list = [0.85]#10, 20, 20] 85 | # periodic = false 86 | # 87 | # 88 | parset_name = "gamma-rg0_2" 89 | var1_list = round.(range(0.88* 0.2 , 0.88* 1.5; length= 6), digits= 2) # gamma\ # gamma 90 | #var1_list = round.(range(0.88* 0.2 , 0.88* 1.5; length= 10), digits= 2) # gamma\ # gamma 91 | sort!(push!(var1_list, 0.88)) 92 | var2_list = round.(range(0.80 , 1/0.80; length= 10), digits= 2) 93 | #[2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6] # c_beta_parameter 94 | var3_list = [50]#10, 20, 20] 95 | periodic = false 96 | 97 | str_list =[] 98 | arg_list = [] 99 | for var1 in var1_list 100 | for var2 in var2_list 101 | for var3 in var3_list 102 | push!(str_list , ) 103 | 104 | ID = concat_str([ make_str("U", var1), make_str("DT", var2),make_str("Nx", var3) ]) # "U10-DT" 105 | #ID = concat_str([ make_str("rg", var2, 2), make_str("gamma", var1, 2),make_str("Nx", var3) ]) 106 | 107 | #ID = concat_str([ make_str("gamma", var1, 2), make_str("cbeta", var2, 1),make_str("Nx", var3) ]) # "gamma-c_beta" 108 | ID = concat_str([ make_str("gamma", var1, 2), make_str("rg", var2, 1),make_str("Nx", var3) ]) # "gamma-rg_2" 109 | 110 | arg_case = [ "--ID", ID, 111 | #"--U10", @sprintf("%i",var1), 112 | #"--c_beta", @sprintf("%0.2f",var2), 113 | "--gamma", @sprintf("%0.2f",var1), 114 | "--r_g0", @sprintf("%0.2f",var2), 115 | "--Nx", @sprintf("%i",var3), 116 | #"--DT", @sprintf("%i",var2), 117 | "--parset", parset_name] 118 | if periodic 119 | push!(arg_case, "--periodic") 120 | end 121 | push!(arg_list , arg_case) 122 | @show arg_case 123 | end 124 | end 125 | end 126 | 127 | 128 | 129 | #localARGS= arg_list[5] 130 | 131 | # 132 | #aa = ["--ID", "Lx30_DT30_U10", "--Lx", 30, "--DT", 30, "--U", 10] 133 | #push!(aa, "--periodic") 134 | # ARGS = [ "--ID", "test1", 135 | # "--Lx", "20", 136 | # "--T", "24", 137 | # "--DT", "30"] 138 | 139 | #include("./run_fake.jl")#, ARGS=["--foo", "123"]) 140 | # %% 141 | localARGS = arg_list[3] 142 | 143 | #mkdir(pwd()* "/data/" * parset * "/" ) 144 | completed_runs = readdir( pwd()* "/data/" * parset_name * "/" ) 145 | 146 | 147 | @show completed_runs 148 | #@show arg_list 149 | # include( joinpath(pwd(), "parameter_test/") * "/run_fake.jl") 150 | # localARGS 151 | 152 | for args in arg_list 153 | global localARGS = args 154 | #push!(empty!(localARGS), args) 155 | @show localARGS 156 | 157 | if args[2] in completed_runs 158 | @printf "runner : case exist, obmitted " 159 | else 160 | @printf "runner : run code: " 161 | #include( joinpath( pwd(), "parameter_test/") * "/run_fake.jl") 162 | include( joinpath( pwd(), "code/") * "/run_1D.jl") 163 | end 164 | @printf "\n runner : next\n" 165 | 166 | end 167 | 168 | #run(pipeline( `julia -e 'print("hello")' ` , `grep el`)) 169 | #localARGS 170 | #run( `julia` ) 171 | 172 | # %% 173 | # function do_run(args) 174 | # localARGS = args 175 | # #@show "before pass", localARGS 176 | # include("./run_fake.jl") 177 | # end 178 | 179 | #@everywhere carrier(argi) = x -> arg_list[x] 180 | 181 | # @everywhere carrier(f) = x -> f(x) 182 | # 183 | # 184 | # carrier(do_run)(arg_list[1]) 185 | # 186 | # carrier( remesh!, State, t) 187 | # 188 | # ParticleCollection = fetch(pmap(carrier( remesh!, State, t) ,advance_workers, arg_list )); 189 | -------------------------------------------------------------------------------- /src/old_structure/run_collections_varying_forcing.jl: -------------------------------------------------------------------------------- 1 | using Printf 2 | 3 | 4 | # using Distributed 5 | # addprocs(2) 6 | # advance_workers = WorkerPool([2, 3]) 7 | 8 | push!(LOAD_PATH, joinpath(pwd(), "code/") ) 9 | # %% 10 | 11 | function make_str(name::String, value::Number) 12 | return name*@sprintf("%i",value) 13 | end 14 | 15 | 16 | function make_str(name::String, value::Number, digits::Number) 17 | return name*@sprintf("%0.2f",round(value, digits= digits) ) 18 | end 19 | 20 | 21 | function concat_str(alist) 22 | str_list ="" 23 | for ai in alist 24 | str_list *= ai * "_" 25 | end 26 | return str_list[1:end-1] 27 | end 28 | 29 | 30 | function concat_str_space(alist) 31 | str_list ="" 32 | for ai in alist 33 | str_list *= ai * " " 34 | end 35 | return str_list[1:end-1] 36 | end 37 | 38 | make_str 39 | 40 | # %% 41 | 42 | base_parset="1D_gaussian" 43 | parset_name = "Nx-DT" 44 | var1_list = [20,50, 100, 150, 200, 300] 45 | var2_list = [5, 10, 15, 20, 30, 40, 50, 60] 46 | periodic = false 47 | 48 | 49 | # parset_name = "Nx-DT-periodic" 50 | # var1_list = [10] 51 | # var2_list = [3, 5, 10, 15, 20, 30, 60] 52 | # var3_list = [5, 8, 10, 20, 30, 40, 50, 80] 53 | # periodic = true 54 | 55 | 56 | str_list =[] 57 | arg_list = [] 58 | for var1 in var1_list 59 | for var2 in var2_list 60 | push!(str_list , ) 61 | 62 | ID = concat_str([ make_str("Nx", var1), make_str("DT", var2) ]) # "U10-DT" 63 | #ID = concat_str([ make_str("rg", var2, 2), make_str("gamma", var1, 2),make_str("Nx", var3) ]) 64 | 65 | #ID = concat_str([ make_str("gamma", var1, 2), make_str("cbeta", var2, 1),make_str("Nx", var3) ]) # "gamma-c_beta" 66 | 67 | arg_case = [ "--ID", ID, 68 | "--Nx", @sprintf("%i",var1), 69 | #"--U10", @sprintf("%i",var1), 70 | #"--c_beta", @sprintf("%0.2f",var2), 71 | #"--gamma", @sprintf("%0.2f",var1), 72 | #"--rg", @sprintf("%0.2f",var2), 73 | "--DT", @sprintf("%i",var2), 74 | "--parset", parset_name] 75 | if periodic 76 | push!(arg_case, "--periodic") 77 | end 78 | push!(arg_list , arg_case) 79 | @show arg_case 80 | end 81 | end 82 | 83 | 84 | 85 | #localARGS= arg_list[5] 86 | 87 | # 88 | #aa = ["--ID", "Lx30_DT30_U10", "--Lx", 30, "--DT", 30, "--U", 10] 89 | #push!(aa, "--periodic") 90 | # ARGS = [ "--ID", "test1", 91 | # "--Lx", "20", 92 | # "--T", "24", 93 | # "--DT", "30"] 94 | 95 | #include("./run_fake.jl")#, ARGS=["--foo", "123"]) 96 | mkdir(pwd()* "/data/"*base_parset*"/" * parset_name * "/") 97 | 98 | # %% 99 | localARGS = arg_list[3] 100 | 101 | completed_runs = readdir( pwd()* "/data/"*base_parset*"/" * parset_name * "/" ) 102 | 103 | 104 | @show completed_runs 105 | #@show arg_list 106 | # include( joinpath(pwd(), "parameter_test/") * "/run_fake.jl") 107 | # localARGS 108 | 109 | for args in arg_list 110 | localARGS = args 111 | #push!(empty!(localARGS), args) 112 | @show localARGS 113 | 114 | if args[2] in completed_runs 115 | @printf "runner : case exist, obmitted " 116 | else 117 | @printf "runner : run code: " 118 | #include( joinpath( pwd(), "parameter_test/") * "/run_fake.jl") 119 | include( joinpath( pwd(), "code/") * "/run_1D_time_varing_forcing.jl") 120 | end 121 | @printf "\n runner : next\n" 122 | 123 | end 124 | 125 | #run(pipeline( `julia -e 'print("hello")' ` , `grep el`)) 126 | #localARGS 127 | #run( `julia` ) 128 | 129 | # %% 130 | # function do_run(args) 131 | # localARGS = args 132 | # #@show "before pass", localARGS 133 | # include("./run_fake.jl") 134 | # end 135 | 136 | #@everywhere carrier(argi) = x -> arg_list[x] 137 | 138 | # @everywhere carrier(f) = x -> f(x) 139 | # 140 | # 141 | # carrier(do_run)(arg_list[1]) 142 | # 143 | # carrier( remesh!, State, t) 144 | # 145 | # ParticleCollection = fetch(pmap(carrier( remesh!, State, t) ,advance_workers, arg_list )); 146 | -------------------------------------------------------------------------------- /src/visualization/Plotting.jl: -------------------------------------------------------------------------------- 1 | module Plotting 2 | 3 | export movie, PlotState_SingleGlobe, PlotState_DoubleGlobe 4 | 5 | # include("../Simulations/Simulations.jl") 6 | # using .Simulations 7 | 8 | using ..Simulations: convert_store_to_tuple, CashStore, StateStore, Simulation 9 | using ..ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 10 | 11 | include("plotting_1D.jl") 12 | include("movie_2D.jl") 13 | include("global.jl") 14 | 15 | using .movie 16 | 17 | end -------------------------------------------------------------------------------- /src/visualization/plotting_1D.jl: -------------------------------------------------------------------------------- 1 | using Plots 2 | 3 | """ 4 | plot_results(wave_simulation::Simulation; wind_grid=nothing) 5 | plot the results of a simulation in a simple way 6 | """ 7 | function plot_results(wave_simulation; wind_grid=nothing, title="") 8 | output = convert_store_to_tuple(wave_simulation.store, wave_simulation) 9 | 10 | store_waves_energy = output.data[:, :, 1] 11 | store_waves_mx = output.data[:, :, 2] 12 | #store_waves_my = output.data[:, :, 3]; 13 | cg = store_waves_energy ./ store_waves_mx ./ 2 14 | 15 | gr(display_type=:inline) 16 | 17 | dx = wave_simulation.model.grid.dx 18 | DT = wave_simulation.model.ODEsettings.timestep 19 | # ## make a three panel plot for energy, mx, and cg 20 | p1 = heatmap(output.x / dx, output.time / DT, store_waves_energy, levels=20, colormap=:dense) 21 | p2 = heatmap(output.x / dx, output.time / DT, store_waves_mx, levels=20, colormap=:dense) 22 | p3 = heatmap(output.x / dx, output.time / DT, cg, levels=40, colormap=:dense) 23 | 24 | if wind_grid != nothing 25 | # add wind forcing to plot 26 | contour!(p1, wind_grid.x / dx, wind_grid.t / DT, transpose(wind_grid.u) / 10, levels=5, colormap=:black) 27 | contour!(p2, wind_grid.x / dx, wind_grid.t / DT, transpose(wind_grid.u) / 200, levels=5, colormap=:black) 28 | contour!(p3, wind_grid.x / dx, wind_grid.t / DT, transpose(wind_grid.u) / 3, levels=5, colormap=:black) 29 | end 30 | 31 | plot(p1, p2, p3, layout=(3, 1), size=(600, 1200), title=[title * "\nEnergy" "mx" "cg"], xlabel="x (dx)", ylabel="time (DT)", left_margin=10 * Plots.mm) |> display 32 | 33 | end 34 | 35 | -------------------------------------------------------------------------------- /tests/B02_2D_regtest_netCDF.jl: -------------------------------------------------------------------------------- 1 | 2 | 3 | #using Plots 4 | import Plots as plt 5 | using Setfield, IfElse 6 | 7 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 8 | 9 | import PiCLES: FetchRelations, ParticleTools 10 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 11 | using PiCLES.Operators: TimeSteppers 12 | using PiCLES.Simulations 13 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 14 | 15 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 16 | using PiCLES.Models.WaveGrowthModels2D 17 | 18 | using Oceananigans.TimeSteppers: Clock, tick! 19 | import Oceananigans: fields 20 | using Oceananigans.Units 21 | import Oceananigans.Utils: prettytime 22 | 23 | using PiCLES.Architectures 24 | using GLMakie 25 | 26 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 27 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 28 | 29 | using NCDatasets 30 | using Interpolations 31 | using Dates: Dates as Dates 32 | 33 | using Revise 34 | 35 | # %% 36 | 37 | save_path = "plots/tests/B02_2D_regtest_netCDF/" 38 | mkpath(save_path) 39 | 40 | save_path_data = "data/work/B02_2D_regtest_netCDF/" 41 | mkpath(save_path_data) 42 | 43 | load_path = "data/work/wind_data_SWAMP/" 44 | 45 | ##### basic parameters 46 | # timestep 47 | DT = 10minutes 48 | # Characterstic wind velocities and std 49 | U10, V10 = 10.0, 10.0 50 | 51 | # Define basic ODE parameters 52 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 53 | 54 | ODEpars 55 | Const_ID 56 | Const_Scg 57 | 58 | function interpolate_winds(ds, multiplyer=0) 59 | 60 | Nxx = Int(ceil(ds.attrib["Nx"] * sqrt(2)^multiplyer)) 61 | Nyy = Int(ceil(ds.attrib["Ny"] * sqrt(2)^multiplyer)) 62 | 63 | # define grid based on 64 | grid = TwoDGrid(ds["x"][end], Nxx, ds["y"][end], Nyy) 65 | grid_mesh = TwoDGridMesh(grid, skip=1) 66 | gn = TwoDGridNotes(grid) 67 | 68 | # define time 69 | time_rel = (ds["time"][:] - ds["time"][1]) ./ convert(Dates.Millisecond, Dates.Second(1)) 70 | T = 1day#hours#time_rel[end] 71 | 72 | nodes = (ds["x"][:], ds["y"][:], time_rel) 73 | u_grid = LinearInterpolation(nodes, permutedims(ds["u10m"], [1, 2, 3]), extrapolation_bc=Flat()) 74 | v_grid = LinearInterpolation(nodes, permutedims(ds["v10m"], [1, 2, 3]), extrapolation_bc=Flat()) 75 | 76 | return grid, grid_mesh, gn, T, u_grid, v_grid 77 | end 78 | 79 | # define ODE system and parameters 80 | #particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q); 81 | 82 | 83 | 84 | Revise.retry() 85 | # Default initial conditions based on timestep and chaeracteristic wind velocity 86 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT) 87 | default_particle = ParticleDefaults(WindSeamin["lne"], WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0) 88 | 89 | function make_reg_test_store(wave_model, save_path_name) 90 | 91 | ### build Simulation 92 | wave_simulation = Simulation(wave_model, Δt=DT, stop_time=wave_model.ODEsettings.total_time)#1hours) 93 | initialize_simulation!(wave_simulation) 94 | 95 | # run simulation & save simulation 96 | init_state_store!(wave_simulation, save_path_name) 97 | #run!(wave_simulation, cash_store=true, debug=true) 98 | run!(wave_simulation, store=true, cash_store=false, debug=false) 99 | close_store!(wave_simulation) 100 | 101 | end 102 | 103 | # or, alternatively, make movie 104 | function make_reg_test_movie(wave_model, save_path_name; N=36) 105 | 106 | wave_simulation = Simulation(wave_model, Δt=DT, stop_time=wave_model.ODEsettings.total_time)#1hours) 107 | initialize_simulation!(wave_simulation) 108 | 109 | fig, n = init_movie_2D_box_plot(wave_simulation, name_string="T01") 110 | #wave_simulation.stop_time += 1hour 111 | #N = 36 112 | #plot_name = "dummy" 113 | record(fig, save_path_name * ".gif", 1:N, framerate=10) do i 114 | @info "Plotting frame $i of $N..." 115 | @info wave_simulation.model.clock 116 | movie_time_step!(wave_simulation.model, wave_simulation.Δt) 117 | 118 | n[] = 1 119 | end 120 | 121 | end 122 | 123 | 124 | # %% 125 | # case = "SWAMP_Case_III" 126 | # ncfile = load_path * case * ".nc" 127 | # ds = Dataset(ncfile, "r") 128 | 129 | # %% 130 | # loop over U10 and V10 range 131 | case_list = ["SWAMP_Case_II", "SWAMP_Case_III", "SWAMP_Case_IV" , "SWAMP_Case_VI", "SWAMP_Case_VII", "SWAMP_Case_VIII"] 132 | # case_list = [ "SWAMP_Case_VI"] 133 | 134 | #case_list = ["SWAMP_Case_IV", "SWAMP_Case_VII", "SWAMP_Case_VIII"] 135 | #for I in CartesianIndices(gridmesh) 136 | for case in case_list 137 | # load netCDF file 138 | #ncfile = "data/work/wind_data/" * case * ".nc" 139 | ncfile = load_path * case * ".nc" 140 | ds = Dataset(ncfile, "r") 141 | 142 | grid, grid_mesh, gn, T, u_grid, v_grid = interpolate_winds(ds) 143 | 144 | u(x, y, t) = u_grid(x, y, t) 145 | v(x, y, t) = v_grid(x, y, t) 146 | winds = (u=u, v=v) 147 | 148 | #winds, u, v =convert_wind_field_functions(u_func, v_func, x, y, t) 149 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q) 150 | 151 | # ... and ODESettings 152 | ODE_settings = PW.ODESettings( 153 | Parameters=ODEpars, 154 | # define mininum energy threshold 155 | log_energy_minimum=WindSeamin["lne"], 156 | #maximum energy threshold 157 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 158 | saving_step=DT, 159 | timestep=DT, 160 | total_time=T, 161 | adaptive=true, 162 | dt=1e-3, #60*10, 163 | dtmin=1e-4, #60*5, 164 | force_dtmin=true, 165 | callbacks=nothing, 166 | save_everystep=false) 167 | 168 | ## Define wave model 169 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 170 | winds=winds, 171 | ODEsys=particle_system, 172 | ODEsets=ODE_settings, # ODE_settings 173 | ODEinit_type="wind_sea", # default_ODE_parameters 174 | periodic_boundary=false, 175 | boundary_type="same", 176 | minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), # 177 | #minimal_state=FetchRelations.MinimalState(2, 2, DT) * 1, 178 | movie=true) 179 | 180 | 181 | NN = Int(floor(wave_model.ODEsettings.total_time / wave_model.ODEsettings.timestep)) 182 | 183 | # for saving data 184 | # when saving data 185 | save_path_select = save_path_data 186 | mkpath(save_path_select * case) 187 | make_reg_test_store(wave_model, save_path_select * case) 188 | 189 | #when plotting data 190 | # save_path_select = save_path 191 | #make_reg_test_movie(wave_model, save_path * case, N=NN) 192 | end 193 | 194 | -------------------------------------------------------------------------------- /tests/B03_2D_regtest_moving_fetch_netCDF.jl: -------------------------------------------------------------------------------- 1 | 2 | 3 | #using Plots 4 | using Pkg 5 | Pkg.activate("PiCLES/") 6 | # Pkg.activate("../") 7 | 8 | import Plots as plt 9 | using Setfield, IfElse 10 | 11 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 12 | 13 | import PiCLES: FetchRelations, ParticleTools 14 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 15 | using PiCLES.Operators: TimeSteppers 16 | using PiCLES.Simulations 17 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 18 | 19 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 20 | using PiCLES.Models.WaveGrowthModels2D 21 | 22 | using Oceananigans.TimeSteppers: Clock, tick! 23 | import Oceananigans: fields 24 | using Oceananigans.Units 25 | import Oceananigans.Utils: prettytime 26 | 27 | using PiCLES.Architectures 28 | #using GLMakie 29 | 30 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 31 | # using PiCLES.Plotting.movie: init_movie_2D_box_plot 32 | 33 | using NCDatasets 34 | using Interpolations 35 | using Dates: Dates as Dates 36 | using Revise 37 | 38 | # %% 39 | save_path = "plots/tests/B03_2D_regtest_moving_fetch_netCDF/" 40 | mkpath(save_path) 41 | 42 | save_path_data = "data/work/B03_2D_regtest_moving_fetch_netCDF_local/" 43 | mkpath(save_path_data) 44 | 45 | load_path = "data/work/wind_data_moving_fetch/" 46 | # load_path = "/glade/work/mhell/2022_particle_waves/wind_data_moving_fetch/" 47 | #load_path = "data/work/wind_data_SWAMP/" 48 | 49 | ##### basic parameters 50 | # timestep 51 | DT = 30minutes 52 | 53 | # Define basic ODE parameters 54 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 55 | Revise.retry() 56 | 57 | function interpolate_winds(ds, multiplyer=0) 58 | 59 | Nxx = Int(ceil(ds.attrib["Nx"] * sqrt(2)^multiplyer)) 60 | Nyy = Int(ceil(ds.attrib["Ny"] * sqrt(2)^multiplyer)) 61 | 62 | # define grid based on 63 | grid = TwoDGrid(ds["x"][end], Nxx, ds["y"][end], Nyy) 64 | grid_mesh = TwoDGridMesh(grid, skip=1) 65 | gn = TwoDGridNotes(grid) 66 | 67 | # define time 68 | time_rel = (ds["time"][:] - ds["time"][1]) ./ convert(Dates.Millisecond, Dates.Second(1)) 69 | T = time_rel[end] 70 | 71 | nodes = (ds["x"][:], ds["y"][:], time_rel) 72 | u_grid = LinearInterpolation(nodes, permutedims(ds["u10m"], [1, 2, 3]), extrapolation_bc=Flat()) 73 | v_grid = LinearInterpolation(nodes, permutedims(ds["v10m"], [1, 2, 3]), extrapolation_bc=Flat()) 74 | 75 | return grid, grid_mesh, gn, T, u_grid, v_grid 76 | end 77 | 78 | # define ODE system and parameters 79 | #particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q); 80 | 81 | Revise.retry() 82 | # Default initial conditions based on timestep and chaeracteristic wind velocity 83 | WindSeamin = FetchRelations.MinimalWindsea(2, 2, DT) 84 | 85 | function make_reg_test_store(wave_model, save_path_name) 86 | 87 | ### build Simulation 88 | wave_simulation = Simulation(wave_model, Δt=DT, stop_time=wave_model.ODEsettings.total_time)#1hours) 89 | initialize_simulation!(wave_simulation) 90 | 91 | # run simulation & save simulation 92 | init_state_store!(wave_simulation, save_path_name) 93 | #run!(wave_simulation, cash_store=true, debug=true) 94 | run!(wave_simulation, store=true, cash_store=false, debug=false) 95 | close_store!(wave_simulation) 96 | 97 | end 98 | 99 | # or, alternatively, make movie 100 | function make_reg_test_movie(wave_model, save_path_name; N=36) 101 | 102 | wave_simulation = Simulation(wave_model, Δt=DT, stop_time=wave_model.ODEsettings.total_time)#1hours) 103 | initialize_simulation!(wave_simulation) 104 | 105 | fig, n = init_movie_2D_box_plot(wave_simulation, resolution=(1800, 1200), name_string="T01") 106 | #wave_simulation.stop_time += 1hour 107 | #N = 36 108 | #plot_name = "dummy" 109 | record(fig, save_path_name * ".gif", 1:N, framerate=10) do i 110 | @info "Plotting frame $i of $N..." 111 | @info wave_simulation.model.clock 112 | movie_time_step!(wave_simulation.model, wave_simulation.Δt) 113 | 114 | n[] = 1 115 | end 116 | 117 | end 118 | 119 | 120 | # %% 121 | # case = "SWAMP_Case_III" 122 | # ncfile = load_path * case * ".nc" 123 | # ds = Dataset(ncfile, "r") 124 | 125 | # %% 126 | # loop over U10 and V10 range 127 | # case_list = ["MF_Case_I"]#, "MF_Case_II", "MF_Case_III", "MF_Case_IV" ] 128 | case_list = ["MF_Case_I", "MF_Case_II", "MF_Case_III", "MF_Case_IV"] 129 | #case_list = [ "SWAMP_Case_VIII"] 130 | #for I in CartesianIndices(gridmesh) 131 | for case in case_list 132 | # load netCDF file 133 | #ncfile = "data/work/wind_data/" * case * ".nc" 134 | ncfile = load_path * case * ".nc" 135 | ds = Dataset(ncfile, "r") 136 | 137 | grid, grid_mesh, gn, T, u_grid, v_grid = interpolate_winds(ds) 138 | 139 | @info "total time ", T 140 | 141 | u(x, y, t) = u_grid(x, y, t) 142 | v(x, y, t) = v_grid(x, y, t) 143 | winds = (u=u, v=v) 144 | 145 | #winds, u, v =convert_wind_field_functions(u_func, v_func, x, y, t) 146 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q) 147 | 148 | # ... and ODESettings 149 | ODE_settings = PW.ODESettings( 150 | Parameters=ODEpars, 151 | # define mininum energy threshold 152 | log_energy_minimum=WindSeamin["lne"], 153 | #maximum energy threshold 154 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 155 | saving_step=DT, 156 | timestep=DT, 157 | total_time=T, 158 | adaptive=true, 159 | dt=1e-3, #60*10, 160 | dtmin=1e-4, #60*5, 161 | force_dtmin=true, 162 | save_everystep=false) 163 | 164 | ## Define wave model 165 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 166 | winds=winds, 167 | ODEsys=particle_system, 168 | ODEsets=ODE_settings, # ODE_settings 169 | ODEinit_type="wind_sea", # default_ODE_parameters 170 | periodic_boundary=false, 171 | boundary_type="same", 172 | minimal_particle=FetchRelations.MinimalParticle(2, 2, DT), # 173 | movie=true) 174 | 175 | 176 | NN = Int(floor(wave_model.ODEsettings.total_time / wave_model.ODEsettings.timestep)) 177 | 178 | # for saving data 179 | # when saving data 180 | save_path_select = save_path_data 181 | mkpath(save_path_select * case) 182 | make_reg_test_store(wave_model, save_path_select * case) 183 | 184 | # when plotting data 185 | # save_path_select = save_path 186 | # make_reg_test_movie(wave_model, save_path * case, N=NN) 187 | end 188 | # %% 189 | -------------------------------------------------------------------------------- /tests/S01_grids_Cartesian.jl: -------------------------------------------------------------------------------- 1 | using Pkg 2 | Pkg.activate("PiCLES/") 3 | 4 | using PiCLES.Grids.CartesianGrid: TwoDCartesianGridStatistics, TwoDCartesianGridMesh, ProjetionKernel 5 | #using PiCLES.Grids.TripolarGridMOM6: TripolarGridMOM6, ProjetionKernel 6 | using Plots 7 | 8 | using Revise 9 | using BenchmarkTools 10 | 11 | Revise.retry() 12 | 13 | 14 | # %% testing 15 | grid_stats = TwoDCartesianGridStatistics(0.0, 1.0, 40, 0.0, 1.0, 25) 16 | grid_test = TwoDCartesianGridMesh(grid_stats) 17 | # merge to mesh 18 | TwoDCartesianGridMesh(grid_test, grid_stats) 19 | 20 | # short hand for doing both at ones 21 | G = TwoDCartesianGridMesh(0.0, 1.0, 40, 0.0, 1.0, 25) 22 | 23 | # short hand 24 | G = TwoDCartesianGridMesh(1, 3, 1, 2) 25 | 26 | # add angle definition 27 | G = TwoDCartesianGridMesh(0.0, 39, 40, 0.0, 24, 25; angle=0.5) 28 | # test pojection 29 | M = ProjetionKernel(G) 30 | 31 | # add mask 32 | mask = ones(Bool, size(G.data.x)) # 1 is ocean, 0 is land (?) 33 | mask[10:15, 10:15] .=0 34 | 35 | # reset mesh 36 | grid_w_mask = TwoDCartesianGridMesh(grid_stats; mask=mask) 37 | GM_mask = TwoDCartesianGridMesh(grid_w_mask, grid_stats) 38 | 39 | # test 40 | scatter(GM_mask.data.x[GM_mask.data.mask], GM_mask.data.y[GM_mask.data.mask], color="black", legend=false, markersize=1) 41 | 42 | -------------------------------------------------------------------------------- /tests/S01_grids_Tripolar.jl: -------------------------------------------------------------------------------- 1 | 2 | using Pkg 3 | Pkg.activate("PiCLES/") 4 | 5 | using PiCLES.Grids.TripolarGridMOM6: TripolarGridMOM6, ProjetionKernel 6 | using Plots 7 | 8 | using Revise 9 | using BenchmarkTools 10 | Revise.retry() 11 | 12 | load_path = "PiCLES/src/Grids/files/" 13 | 14 | # %% 15 | for i in [2, 4, 6, 8] 16 | Gtest = TripolarGridMOM6.MOM6GridMesh(load_path * "ocean_hgrid_221123.nc", i) 17 | p = plot() 18 | scatter!(p, Gtest.data.x[Gtest.data.mask], Gtest.data.y[Gtest.data.mask], color="black", legend=false, markersize=1) 19 | display(p) 20 | end 21 | 22 | # %% 23 | 24 | Revise.retry() 25 | 26 | for i in [2,4,6,8] 27 | Gtest = TripolarGridMOM6.MOM6GridMesh(load_path * "ocean_hgrid_221123.nc", i, MaskFile=load_path * "ocean_topo_tx2_3v2_240501.nc") 28 | p = plot() 29 | scatter!(p, Gtest.data.x[Gtest.data.mask], Gtest.data.y[Gtest.data.mask], color="black", legend=false, markersize=1) 30 | display(p) 31 | end 32 | 33 | # %% test projection kernel 34 | G = TripolarGridMOM6.MOM6GridMesh(load_path * "ocean_hgrid_221123.nc", 4, MaskFile=load_path * "ocean_topo_tx2_3v2_240501.nc") 35 | @benchmark M = ProjetionKernel(G) 36 | M = ProjetionKernel(G) 37 | 38 | # this shows all potions where the kernel is nothing 39 | scatter( G.data.x[isnothing.(M)], G.data.y[isnothing.(M)], color="black", legend=false, markersize=1) 40 | 41 | -------------------------------------------------------------------------------- /tests/S02_2D_box_mesh_grid.jl: -------------------------------------------------------------------------------- 1 | ENV["JULIA_INCREMENTAL_COMPILE"] = true 2 | using Pkg 3 | Pkg.activate("PiCLES/") 4 | 5 | import Plots as plt 6 | using Setfield, IfElse 7 | 8 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 9 | 10 | import PiCLES: FetchRelations, ParticleTools 11 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 12 | using PiCLES.Operators: TimeSteppers 13 | using PiCLES.Simulations 14 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 15 | 16 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 17 | using PiCLES.Grids.CartesianGrid: TwoDCartesianGridMesh, ProjetionKernel, TwoDCartesianGridStatistics 18 | 19 | using PiCLES.Models.WaveGrowthModels2D 20 | 21 | using Oceananigans.TimeSteppers: Clock, tick! 22 | import Oceananigans: fields 23 | using Oceananigans.Units 24 | import Oceananigans.Utils: prettytime 25 | 26 | using PiCLES.Architectures 27 | using PiCLES.Architectures: AbstractGridStatistics, CartesianGridStatistics 28 | 29 | 30 | using Plots 31 | 32 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 33 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 34 | 35 | using Revise 36 | 37 | using StructArrays 38 | using BenchmarkTools 39 | 40 | using GLMakie 41 | 42 | 43 | # %% 44 | save_path = "plots/tests/S02_box_2D_mesh_grid/" 45 | mkpath(save_path) 46 | pwd() 47 | # % Parameters 48 | U10, V10 = -15.0, 15.0#15.0 49 | DT = 20minutes 50 | 51 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 52 | 53 | # u(x, y, t) = 0.01 + U10 * sin(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) 54 | # v(x, y, t) = 0.01 - V10 * cos(t / (6*60*60 * 2π) ) * sin(x / 50e3) * sin(y / 50e3) 55 | u_std = 200e3 * 1 56 | v_std = 200e3 * 1 57 | # 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π)) 58 | # 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π)) 59 | # u_func(x, y, t) = U10 * exp(-(x - 250e3)^2 / u_std^2) * exp(-(y - 250e3)^2 / v_std^2) #* sin(t * 2 / (1 * 60 * 60 * 2π)) 60 | # v_func(x, y, t) = V10 * exp(-(x - 250e3)^2 / u_std^2) * exp(-(y - 250e3)^2 / v_std^2) #* cos(t * 2 / (1 * 60 * 60 * 2π)) 61 | 62 | # u(x, y, t) = IfElse.ifelse.(x .< 250e3, U10, -3.00) + y * 0 + t * 0 63 | # v(x, y, t) = (IfElse.ifelse.(x .< 250e3, V10, 0.00) + y * 0) + t *0 #.* cos(t * 5 / (1 * 60 * 60 * 2π)) 64 | 65 | # u(x, y, t) = IfElse.ifelse.(x .< 250e3, U10, 1.00) + y * 0 + t * 0 66 | # v(x, y, t) = (IfElse.ifelse.(x .< 250e3, V10, 0.00) + y * 0) + t * 0 #.* cos(t * 5 / (1 * 60 * 60 * 2π)) 67 | 68 | u(x, y, t) = U10 + y * 0 + t * 0 69 | v(x, y, t) = V10 + y * 0 + t * 0 #(V10 + y * 0) .* cos(t * 5 / (1 * 60 * 60 * 2π)) 70 | winds = (u=u, v=v) 71 | 72 | 73 | Revise.retry() 74 | 75 | grid = TwoDCartesianGridMesh(500e3, 51, 400e3, 41; angle=0.0, periodic_boundary=(false, true)) 76 | 77 | Plots.heatmap(grid.data.x[:, 1], grid.data.y[1, :], transpose(grid.data.mask)) 78 | 79 | # % Make fake mask 80 | mask = ones(Bool, size(grid.data.x)) # 1 is ocean, 0 is land (?) 81 | mask[20:35, 20:35] .= 0 82 | # reset mesh with amsk 83 | gridstats_mask = TwoDCartesianGridMesh(grid.stats; mask=mask); 84 | grid = TwoDCartesianGridMesh(gridstats_mask, grid.stats, ProjetionKernel) 85 | 86 | 87 | Revise.retry() 88 | grid.stats.Nx 89 | grid.stats.Ny 90 | 91 | Plots.heatmap(grid.data.x[:,1], grid.data.y[1,:], transpose(grid.data.mask)) 92 | 93 | # x_prime = ProjetionKernel(grid)[1, 1] .* grid.data.x + ProjetionKernel(grid)[1, 2] .* grid.data.y 94 | # y_prime = ProjetionKernel(grid)[2, 1] .* grid.data.x + ProjetionKernel(grid)[2, 2] .* grid.data.y 95 | 96 | 97 | 98 | # %% 99 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q, input=true, dissipation=true); 100 | default_ODE_parameters = (r_g=ODEpars.r_g, C_α=Const_Scg.C_alpha, 101 | C_φ=Const_ID.c_β, C_e=Const_ID.C_e, g=9.81);#, M=M); 102 | 103 | # define setting and standard initial conditions 104 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT); 105 | lne_local = log(WindSeamin["E"]) 106 | cg_u_local = WindSeamin["cg_bar_x"] 107 | cg_v_local = WindSeamin["cg_bar_y"] 108 | 109 | ODE_settings = PW.ODESettings( 110 | Parameters=default_ODE_parameters, 111 | # define mininum energy threshold 112 | log_energy_minimum=lne_local,#log(FetchRelations.Eⱼ(0.1, DT)), 113 | #maximum energy threshold 114 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 115 | saving_step=DT, 116 | timestep=DT, 117 | total_time=T = 6days, 118 | adaptive=true, 119 | dt=1e-3, #60*10, 120 | dtmin=1e-4, #60*5, 121 | force_dtmin=true, 122 | callbacks=nothing, 123 | save_everystep=false) 124 | 125 | 126 | default_particle = ParticleDefaults(lne_local, cg_u_local, cg_v_local, 0.0, 0.0) 127 | 128 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 129 | winds=winds, 130 | ODEsys=particle_system, 131 | ODEsets=ODE_settings, # ODE_settings 132 | ODEinit_type="wind_sea", # default_ODE_parameters 133 | periodic_boundary=false, 134 | boundary_type="same", 135 | #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), 136 | movie=true) 137 | 138 | 139 | Revise.retry() 140 | 141 | # ### build Simulation 142 | wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=4hours)#1hours) 143 | # wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=30minutes)#1hours) 144 | initialize_simulation!(wave_simulation); 145 | 146 | Plots.heatmap(transpose(wave_model.ParticleCollection.on)) 147 | Plots.heatmap(transpose(wave_model.ParticleCollection.boundary)) 148 | 149 | 150 | # run simulation 151 | # run!(wave_simulation, cash_store=true, debug=true) 152 | # or, alternatively, make movie 153 | 154 | fig, n = init_movie_2D_box_plot(wave_simulation) 155 | 156 | #wave_simulation.stop_time += 1hour 157 | N = 26 *5 158 | # plot_name = "2D_box_masked_test_half_domain_diagonal_angle30" 159 | plot_name = "2D_box_masked_test_half_domain_zonal" 160 | record(fig, save_path * plot_name * ".gif", 1:N, framerate=10) do i 161 | @info "Plotting frame $i of $N..." 162 | @info wave_simulation.model.clock 163 | movie_time_step!(wave_simulation.model, wave_simulation.Δt) 164 | 165 | n[] = 1 166 | end 167 | 168 | # %% 169 | -------------------------------------------------------------------------------- /tests/T01_test_PIC_1D.jl: -------------------------------------------------------------------------------- 1 | using Statistics 2 | using Plots 3 | 4 | using PiCLES.ParticleMesh: OneDGrid, OneDGridNotes 5 | import PiCLES.ParticleInCell 6 | 7 | import PiCLES 8 | 9 | function check_sum(charges_1d) 10 | Float64(sum(charges_1d)) #/grid1d.nx 11 | end 12 | 13 | using SharedArrays 14 | 15 | # %% define some functions 16 | plot_path_base = "plots/tests/T01_PIC_1D/with_merge_rule/" 17 | #mkdir(plot_path_base) 18 | 19 | function PIC_loop(grid1d, charges_1d, xp; N= 100, cg= 0.2, verbose=false) 20 | x_collect = [] 21 | p_collect = [] 22 | push!(x_collect, xp) 23 | push!(p_collect, charges_1d) 24 | 25 | #xp = grid1d.x .+ cg0 #.* (1 .+ rand()) 26 | i_charges = charges_1d 27 | 28 | State = SharedMatrix{Float64}(grid1d.Nx, 1) 29 | State .= 0 30 | for ti in 1:1:N 31 | 32 | index_positions, weights = ParticleInCell.compute_weights_and_index(grid1d, xp) 33 | #index_positions = wrap_indexpositons(index_positions, grid1d) 34 | 35 | ParticleInCell.push_to_grid!(State, i_charges, index_positions, weights, grid1d.Nx, true) 36 | 37 | if verbose 38 | @show ip_charges_sum - Float64(sum(State)) 39 | end 40 | 41 | # update charges 42 | i_charges = dropdims(Array{Float64}(State), dims=2)#Array{Float64}(State) #State 43 | 44 | # propagate 45 | xp = grid1dnotes.x .+ cg .* i_charges #.* (0.9 .+ 0.05 *(1 .+ rand(grid1d.Nx))) 46 | #xp = grid1d.x .+ cg0 .* (0.9 .+ 0.05 *(1 .+ rand(grid1d.Nx))) 47 | #xp = grid1d.x .+ 0.1 * (.-0.5 .+ rand(grid1d.Nx)) 48 | #xp = xp .+ 0.1 * (.-0.2 .+ rand(grid1d.Nx)) 49 | 50 | push!(x_collect, xp) 51 | push!(p_collect, copy(State)) 52 | State .= 0 53 | end 54 | return x_collect, p_collect 55 | end 56 | 57 | 58 | function animate(x_collect, p_collect, grid1d; path, name) 59 | 60 | anim = @animate for i in 1:1:length(p_collect) 61 | 62 | scatter(x_collect[i], p_collect[i], label="new") 63 | if i > 1 64 | scatter!(x_collect[i-1], p_collect[i-1], color="gray", alpha=0.4, label="old") 65 | end 66 | title!("sum = $( round(sum(p_collect[i]) )) ") 67 | 68 | ylims!(-0.5, 1.9) 69 | xlims!(grid1d.xmin, grid1d.xmax,) 70 | end 71 | gif(anim, joinpath(path, name * ".gif"), fps=10) 72 | #round(sum(p_collect[1]) ) 73 | end 74 | 75 | function convert_store_to_tuple(p_collect, grid1d) 76 | store_data = cat(p_collect..., dims=2) 77 | store_data = permutedims(store_data, (2, 1)) 78 | x = OneDGridNotes(grid1d).x 79 | steps = collect(range(1, size(store_data)[1], step=1)) 80 | return (data=store_data, x=x, steps=steps) 81 | end 82 | 83 | # %% 84 | Revise.retry() 85 | n_particles = 101 86 | eta_min, eta_max =0, 20 87 | grid1d = OneDGrid(eta_min, eta_max, n_particles) 88 | grid1dnotes = OneDGridNotes(grid1d) 89 | 90 | #grid1d = OneGridPars(grid) 91 | #xp = rand(n_particles) * eta_max 92 | 93 | # make State vector: 94 | State = SharedMatrix{Float64}(grid1d.Nx, 1) 95 | #State = grid1dnotes.x * 0 96 | 97 | # initial charge position 98 | xp = grid1dnotes.x .+ grid1dnotes.dx *1.5 #+ rand(n_particles)/5 99 | 100 | 101 | charges_1d = xp * 0 .- 0.2 102 | charges_1d[40:Int(ceil(grid1d.Nx*2/3))] .=1 103 | 104 | ip_charges_sum = check_sum(charges_1d) 105 | @info "charge sum $(check_sum(charges_1d))" 106 | 107 | # manual step 108 | index_positions, weights = ParticleInCell.compute_weights_and_index(grid1d, xp) 109 | 110 | #index_positions = wrap_indexpositons(index_positions, grid1d) # is part of push_charged_to_gridpoints! 111 | ParticleInCell.push_to_grid!(State, charges_1d, index_positions, weights, grid1d.Nx) 112 | @info "charge sum $(check_sum(State))" 113 | 114 | 115 | plot() 116 | scatter(xp, charges_1d, label ="advected", alpha= 1, s =3 ) 117 | scatter!(grid1dnotes.x, State, color="black", alpha=0.5, s=1, label="new") 118 | 119 | 120 | 121 | # %% 122 | xp = grid1dnotes.x .+ grid1dnotes.dx * 1.5 #+ rand(n_particles)/5 123 | charges_1d = xp * 0 .- 0.2 124 | charges_1d[40:Int(ceil(grid1d.Nx * 2 / 3))] .= 1 125 | 126 | x_collect, p_collect = PIC_loop(grid1d, charges_1d, xp; N=50, cg = 0.2, verbose=true); 127 | 128 | data = convert_store_to_tuple(p_collect, grid1d) 129 | plot() 130 | heatmap(data.x, data.steps, data.data) 131 | #save figure 132 | savefig(joinpath(plot_path_base, "T01_PIC_1D_forward.png")) 133 | 134 | animate(x_collect, p_collect, grid1d, path = plot_path_base, name = "T01_PIC_1D_forward") 135 | 136 | 137 | 138 | # %% 139 | xp = grid1dnotes.x .+ grid1dnotes.dx * 1.5 #+ rand(n_particles)/5 140 | charges_1d = xp * 0 .- 0.2 141 | charges_1d[40:Int(ceil(grid1d.Nx * 2 / 3))] .= 1 142 | 143 | x_collect, p_collect = PIC_loop(grid1d, charges_1d, xp; cg = -0.2, N=50, verbose=true); 144 | 145 | data = convert_store_to_tuple(p_collect, grid1d) 146 | plot() 147 | heatmap(data.x, data.steps, data.data) 148 | savefig(joinpath(plot_path_base, "T01_PIC_1D_backward.png")) 149 | 150 | animate(x_collect, p_collect, grid1d, path = plot_path_base, name = "T01_PIC_1D_backward") 151 | 152 | 153 | # %% 154 | xp = grid1dnotes.x .+ grid1dnotes.dx * 1.5 #+ rand(n_particles)/5 155 | #charges_1d = rand(n_particles)* 0 .+ 1 156 | charges_1d = sin.(xp) *0.2 .+0.2 157 | 158 | x_collect, p_collect = PIC_loop(grid1d, charges_1d, xp; cg =-0.3, N= 50, verbose=true); 159 | animate(x_collect, p_collect, grid1d, path = plot_path_base, name = "T01_PIC_1D_backward_sin") 160 | 161 | data = convert_store_to_tuple(p_collect, grid1d) 162 | plot() 163 | heatmap(data.x, data.steps, data.data) 164 | savefig(joinpath(plot_path_base, "T01_PIC_1D_backward_sin.png")) 165 | animate(x_collect, p_collect, grid1d, path=plot_path_base, name="T01_PIC_1D_backward_sin") 166 | 167 | 168 | 169 | # %% diverging sin 170 | Revise.retry() 171 | xp = grid1dnotes.x .+ grid1dnotes.dx * 1.5 #+ rand(n_particles)/5 172 | #charges_1d = rand(n_particles)* 0 .+ 1 173 | charges_1d = sin.(xp) *0.4 .+0.2 174 | 175 | x_collect, p_collect = PIC_loop(grid1d, charges_1d, xp; cg =-0.3, N= 30, verbose=true); 176 | animate(x_collect, p_collect, grid1d, path=plot_path_base , name="T01_PIC_1D_backward_sin_div") 177 | 178 | data = convert_store_to_tuple(p_collect, grid1d) 179 | plot() 180 | heatmap(data.x, data.steps, data.data) 181 | savefig(joinpath(plot_path_base, "T01_PIC_1D_backward_sin_div.png")) 182 | 183 | animate(x_collect, p_collect, grid1d, path=plot_path_base, name="T01_PIC_1D_backward_sin_div") -------------------------------------------------------------------------------- /tests/T01_test_TemoporalFetchRelatoins.jl: -------------------------------------------------------------------------------- 1 | 2 | using PiCLES: FetchRelations as FR 3 | 4 | plot_path_base = "plots/tests/T01_TemoporalFetchRelatoins/" 5 | mkpath(plot_path_base) 6 | 7 | FR.X_tilde_time_and_fetch 8 | using Plots 9 | 10 | t = range(60, step=5, length=720) 11 | 12 | function plot_windsea_data(t, WS, WS2, WS2m) 13 | cmap = palette(:corkO, 20) 14 | t2 = t / 60 / 60 15 | plot_grid = plot(layout=(2, 2), size=(800, 600), suptitle="Windsea JONSWAP & PM for U10 = -10m/s to 15m/s") 16 | 17 | u_list = -10:2:14 18 | p_dict = Dict() 19 | for (uu, coll) in zip(u_list, cmap[1:end-1]) 20 | plot!(plot_grid[1], t2, WS[uu][!, "E"], label=nothing, color=coll, linewidth= 2) 21 | plot!(plot_grid[2], t2, log.(WS[uu][!, "E"]), label=nothing, color=coll, linewidth= 2) 22 | plot!(plot_grid[3], t2, WS[uu][!, "cg_bar"], label=nothing, color=coll, linewidth= 2) 23 | plot!(plot_grid[4], t2, WS[uu][!, "m"], label=nothing, color=coll, linewidth= 2) 24 | end 25 | 26 | plot!(plot_grid[1], t2, WS2[!, "E"], label="U10 = +-2m/s", color="red", linestyle=:solid) 27 | plot!(plot_grid[1], ylim=(0, 0.01), title="Energy", ylabel="Energy (m^2)", legend=:topright, grid=true) 28 | plot!(plot_grid[2], t2, log.(WS2[!, "E"]), label="U10 = +-2m/s", color="red", linestyle=:solid, title="log(Energy)", ylabel="log(Energy)", grid=true) 29 | plot!(plot_grid[3], t2, WS2[!, "cg_bar"], label="U10 = +-2m/s", color="red", linestyle=:solid, title="cg_bar", ylabel="Cg_bar (m/s)", xlabel="Time scale (hours)", grid=true) 30 | plot!(plot_grid[4], t2, WS2[!, "m"], label="U10 = +-2m/s", color="red", linestyle=:solid, title="Momentum", ylabel="momentum", xlabel="Time scale (hours)", ylim=(-0.002, 0.002), grid=true) 31 | # negative windsea with -2 m/s 32 | plot!(plot_grid[1], t2, WS2m[!, "E"], label=nothing, color="red", linestyle=:solid) 33 | plot!(plot_grid[2], t2, log.(WS2m[!, "E"]), label=nothing, color="red", linestyle=:solid) 34 | plot!(plot_grid[3], t2, WS2m[!, "cg_bar"], label=nothing, color="red", linestyle=:solid) 35 | plot!(plot_grid[4], t2, WS2m[!, "m"], label=nothing, color="red", linestyle=:solid) 36 | 37 | plot(plot_grid) 38 | end 39 | # %% 40 | using DataFrames 41 | 42 | # Example usage: 43 | t = range(60, step=5, length=720) 44 | WS = Dict{Float64, Any}() 45 | for uu in range(-10, step=2, stop=14) 46 | WS1 = FR.get_initial_windsea.(uu, t, "JONSWAP") 47 | WS1 = vcat(DataFrame.(WS1)...) 48 | WS[uu] =WS1 49 | #push!(WS, WS1) 50 | end 51 | WS 52 | 53 | WS2 = vcat(DataFrame.(FR.get_initial_windsea.(2, t))...) 54 | WS2m = vcat(DataFrame.(FR.get_initial_windsea.(-2, t))...) 55 | 56 | WSPM = Dict{Float64, Any}() 57 | for uu in range(-10, step=2, stop=14) 58 | WS1 = FR.get_initial_windsea.(10.0, t, "PM") 59 | WS1 = vcat(DataFrame.(WS1)...) 60 | WSPM[uu] = WS1 61 | end 62 | plot_windsea_data(t, WS, WS2, WS2m) 63 | savefig(joinpath([plot_path_base, "T01_FR_1D_compare.png"])) 64 | 65 | # %% compare with 2D version 66 | function plot_windsea_data_compare(WS1d, WS2d, u10, v10) 67 | 68 | case_string = "u10 = $u10 m/s, v10 = $v10 m/s" 69 | case_string1d = "|U| = $uabs m/s" 70 | 71 | plot_grid = plot(layout=(2, 2), size=(800, 600), subtitle="Windsea JONSWAP & PM for U10 = -10m/s to 15m/s") 72 | 73 | plot!(plot_grid[1], WS1d[!, "E"], label="1D, " * case_string1d, title="Energy | " * case_string, ylabel="Energy (m^2)", legend=:topright, grid=true, linewidth=3, color="black", alpha=0.2) 74 | plot!(plot_grid[1], WS2d[!, "E"], label="2D, " * case_string, linewidth=1.5, color="red") 75 | 76 | plot!(plot_grid[2], log.(WS1d[!, "E"]), label="1D, " * case_string1d, title="log(Energy)", ylabel="log(Energy)", grid=true, linewidth=3, color="black", alpha=0.2) 77 | plot!(plot_grid[2], log.(WS2d[!, "E"]), label="2D, " * case_string, linewidth=1.5, color="red") 78 | 79 | plot!(plot_grid[3], WS1d[!, "cg_bar"], label="1D, " * case_string1d, title="cg_bar", ylabel="Cg_bar (m/s)", xlabel="Time scale (hours)", grid=true, linewidth=4, color="black", alpha=0.2) 80 | plot!(plot_grid[3], WS2d[!, "cg_bar"], label="2D, " * case_string, linewidth=1.5, color="red") 81 | plot!(plot_grid[3], WS2d[!, "cg_bar_x"], label="2D, x, " * case_string, linewidth=1.5, color="blue") 82 | plot!(plot_grid[3], WS2d[!, "cg_bar_y"], label="2D, y, " * case_string, linewidth=1.5, color="green") 83 | 84 | plot!(plot_grid[4], WS1d[!, "m"], label="1D, " * case_string1d, title="Momentum", ylabel="momentum", xlabel="Time scale (hours)", ylim=(-0.001, 0.001), grid=true, linewidth=3, color="black", alpha=0.2) 85 | plot!(plot_grid[4], WS2d[!, "m_x"], label="2D m_x, " * case_string, linewidth=1.5, color="blue") 86 | plot!(plot_grid[4], WS2d[!, "m_y"], label="2D m_y, " * case_string, linewidth=1.5, color="green") 87 | plot(plot_grid) 88 | end 89 | 90 | u10, v10 = -2, 0 91 | uabs = sqrt(u10^2 + v10^2) 92 | WS1d = vcat(DataFrame.(FR.get_initial_windsea.(uabs, t))...) 93 | WS2d = vcat(DataFrame.(FR.get_initial_windsea.(u10, v10, t))...) 94 | 95 | plot_windsea_data_compare(WS1d, WS2d, u10, v10) 96 | 97 | plot_string = "u10_$u10"* "_v10_$v10" 98 | savefig(joinpath([plot_path_base, "T01_FR_" * plot_string * ".png"])) 99 | 100 | 101 | u10, v10 = -2, 2 102 | uabs = sqrt(u10^2 + v10^2) 103 | WS1d = vcat(DataFrame.(FR.get_initial_windsea.(uabs, t))...) 104 | WS2d = vcat(DataFrame.(FR.get_initial_windsea.(u10, v10, t))...) 105 | 106 | plot_windsea_data_compare(WS1d, WS2d, u10, v10) 107 | plot_string = "u10_$u10" * "_v10_$v10" 108 | savefig(joinpath([plot_path_base, "T01_FR_" * plot_string * ".png"])) 109 | 110 | 111 | u10, v10 = -2, -2 112 | uabs = sqrt(u10^2 + v10^2) 113 | WS1d = vcat(DataFrame.(FR.get_initial_windsea.(uabs, t))...) 114 | WS2d = vcat(DataFrame.(FR.get_initial_windsea.(u10, v10, t))...) 115 | 116 | plot_windsea_data_compare(WS1d, WS2d, u10, v10) 117 | plot_string = "u10_$u10" * "_v10_$v10" 118 | savefig(joinpath([plot_path_base, "T01_FR_" * plot_string * ".png"])) 119 | 120 | u10, v10 = 0, -2 121 | uabs = sqrt(u10^2 + v10^2) 122 | WS1d = vcat(DataFrame.(FR.get_initial_windsea.(uabs, t))...) 123 | WS2d = vcat(DataFrame.(FR.get_initial_windsea.(u10, v10, t))...) 124 | 125 | plot_windsea_data_compare(WS1d, WS2d, u10, v10) 126 | plot_string = "u10_$u10" * "_v10_$v10" 127 | savefig(joinpath([plot_path_base, "T01_FR_" * plot_string * ".png"])) 128 | 129 | u10, v10 = 3, -5 130 | uabs = sqrt(u10^2 + v10^2) 131 | WS1d = vcat(DataFrame.(FR.get_initial_windsea.(uabs, t))...) 132 | WS2d = vcat(DataFrame.(FR.get_initial_windsea.(u10, v10, t))...) 133 | 134 | plot_windsea_data_compare(WS1d, WS2d, u10, v10) 135 | plot_string = "u10_$u10" * "_v10_$v10" 136 | savefig(joinpath([plot_path_base, "T01_FR_" * plot_string * ".png"])) 137 | 138 | -------------------------------------------------------------------------------- /tests/T02_single_paticle_2d_benchmark.jl: -------------------------------------------------------------------------------- 1 | 2 | # %% 3 | using DifferentialEquations 4 | using Plots 5 | using Setfield 6 | 7 | 8 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 9 | 10 | import PiCLES: FetchRelations, ParticleTools 11 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleValues, InitParticleInstance 12 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes 13 | using Oceananigans.Units 14 | 15 | using BenchmarkTools 16 | #using Revise 17 | using Profile 18 | # debugging: 19 | 20 | # %% 21 | 22 | plot_path_base = "plots/tests/T04_2D_single_particle/" 23 | mkpath(plot_path_base) 24 | 25 | function set_u_and_t!(integrator, u_new, t_new) 26 | integrator.u = u_new 27 | integrator.t = t_new 28 | end 29 | 30 | 31 | # %% Parameters 32 | U10, V10 = +10.0, +10.0 33 | 34 | # version 3 35 | r_g0 = 0.85 36 | # function to define constants for grouwth and dissipation 37 | 38 | # 39 | Const_Scg = PW.get_Scg_constants() 40 | 41 | #u(x, y, t) = 0.01 - U10 * sin(t / (6 * 60 * 60 * 2π)) 42 | #v(x, y, t) = 0.01 - V10 * cos(t / (6 * 60 * 60 * 2π)) 43 | 44 | #u(x, y, t) = - U10 + 0.01 + x * 0 + y * 0 + t *0 45 | #v(x, y, t) = + V10 + 0.01 + x * 0 + y * 0 + t *0 46 | 47 | u(x, y, t) = (U10 * cos(t / (3 * 60 * 60 * 2π)) + 0.1) + x * 0 + y * 0 48 | v(x, y, t) = -(V10 * sin(t / (3 * 60 * 60 * 2π)) + 0.1) + x * 0 + y * 0 49 | 50 | winds = (u=u, v=v) 51 | 52 | Revise.retry() 53 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q) 54 | typeof(particle_system) 55 | 56 | particle_system 57 | # define V4 parameters absed on Const NamedTuple: 58 | default_ODE_parameters = ( 59 | r_g=r_g0, 60 | C_α=Const_Scg.C_alpha, 61 | C_φ=Const_ID.c_β, 62 | C_e=Const_ID.C_e, 63 | g=9.81, 64 | ) 65 | 66 | # define simple callback 67 | condition(u, t, integrator) = 0.9 * u[1] > log(17) 68 | affect!(integrator) = terminate!(integrator) 69 | cb = ContinuousCallback(condition, affect!) 70 | 71 | # define standard initial conditions 72 | DT = 4hours 73 | WindSeamin = FetchRelations.get_initial_windsea(u(0, 0, 0), v(0, 0, 0), DT / 2) 74 | #WindSeamin = FetchRelations.MinimalWindsea(u(0, 0, 0), v(0, 0, 0), 20minutes) 75 | 76 | ODE_settings = PW.ODESettings( 77 | Parameters=default_ODE_parameters, 78 | # define mininum energy threshold 79 | log_energy_minimum=log(WindSeamin["E"]), 80 | #maximum energy threshold 81 | log_energy_maximum=log(17), # correcsponds to Hs about 16 m 82 | saving_step=300hours, 83 | timestep=DT, 84 | total_time=T = 6days, 85 | callbacks=cb, 86 | save_everystep=false, 87 | maxiters=1e4, 88 | adaptive=true, 89 | dt=10,#60*10, 90 | dtmin=1,#60*5, 91 | force_dtmin=true, 92 | ) 93 | 94 | grid = TwoDGrid(3, 3, 3, 3) 95 | ParticleState = ParticleDefaults(log(WindSeamin["E"]), WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0) 96 | ParticleState2 = ParticleDefaults(log(WindSeamin["E"]), WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 1.0) 97 | 98 | 99 | # initialize particle given the wind conditions: 100 | #ParticleState = InitParticleValues(copy(particle_defaults), TwoDGridNotes(grid), winds, DT) 101 | 102 | 103 | 104 | function time_step_local!(PI, DT) 105 | "take 1 step over DT" 106 | 107 | @info "proposed dt", get_proposed_dt(PI.ODEIntegrator) / 60 108 | 109 | step!(PI.ODEIntegrator, DT, true) 110 | 111 | #@info "u:", PI.ODEIntegrator.u 112 | #clock_time += DT 113 | last_t = PI.ODEIntegrator.t 114 | 115 | ## define here the particle state at time of resetting 116 | #ui = [log(exp(PI.ODEIntegrator.u[1]) * 0.5), PI.ODEIntegrator.u[2] / 2, PI.ODEIntegrator.u[3] / 2, 0.0, 0.0] 117 | #ui = [lne_local, cg_u_local, cg_v_local, 0.0, 0.0] 118 | ui = PI.ODEIntegrator.u 119 | 120 | #ui = [PI.ODEIntegrator.u[1], PI.ODEIntegrator.u[2], PI.ODEIntegrator.u[3], 0.0, 0.0] 121 | WindSeamin = FetchRelations.get_initial_windsea(u(0, 0, last_t), v(0, 0, last_t), DT / 2) 122 | ui = [log(WindSeamin["E"]), WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0] 123 | 124 | set_u_and_t!(PI.ODEIntegrator, ui, last_t) 125 | # #set_u!(PI.ODEIntegrator, ui) 126 | #reinit!(PI.ODEIntegrator, ui, erase_sol=false, reset_dt=true, reinit_cache=true) 127 | #reinit!(PI3.ODEIntegrator, ui, erase_sol=false, reset_dt=true, reinit_cache=true) 128 | 129 | # #set_t!(PI.ODEIntegrator, last_t ) 130 | u_modified!(PI.ODEIntegrator, true) 131 | 132 | add_saveat!(PI.ODEIntegrator, PI.ODEIntegrator.t) 133 | savevalues!(PI.ODEIntegrator) 134 | 135 | return PI 136 | end 137 | 138 | # %% 139 | @time @allocated PI = InitParticleInstance(particle_system, ParticleState, ODE_settings, (0, 0), false, true) 140 | @time @allocated PI = InitParticleInstance(particle_system, ParticleState2, ODE_settings, (0, 0), false, true) 141 | @time @allocated time_step_local!(PI, DT) 142 | 143 | #@time @allocated time_step_local_replace!(PI, DT) 144 | 145 | # %% 146 | #using ProfileCanvas 147 | @time @allocated PI = InitParticleInstance(particle_system, ParticleState, ODE_settings, (0, 0), false, true) 148 | 149 | DT = 10minutes 150 | DT = 3hours 151 | @profview_allocs @time @allocated time_step_local!(PI, DT) 152 | 153 | @profview_allocs for i in Base.Iterators.take(PI.ODEIntegrator, 30) 154 | #@info "t:", PI.ODEIntegrator.t 155 | #@info "u:", PI.ODEIntegrator.u 156 | #@info "i:", i 157 | time_step_local!(PI, DT) 158 | 159 | end 160 | 161 | 162 | # %% Profiling single time step: 163 | using ProfileView 164 | Revise.retry() 165 | @time @allocated PI = InitParticleInstance(particle_system, ParticleState, ODE_settings, (0, 0), false, true) 166 | @time @allocated time_step_local!(PI, DT) 167 | Revise.retry() 168 | DT = 10minutes 169 | ProfileView.@profview for i in Base.Iterators.take(PI.ODEIntegrator, 10) 170 | #@info "t:", PI.ODEIntegrator.t 171 | #@info "u:", PI.ODEIntegrator.u 172 | #@info "i:", i 173 | @time @allocated time_step_local!(PI, DT) 174 | 175 | end 176 | 177 | 178 | 179 | 180 | # % 181 | 182 | # ODEProblem(particle_system, z_initials, (0.0, ODE_settings.total_time), ODE_parameters) 183 | 184 | # %% 185 | -------------------------------------------------------------------------------- /tests/T03_PIC_propagation_2d_blob.jl: -------------------------------------------------------------------------------- 1 | # %% 2 | # ENV["JULIA_INCREMENTAL_COMPILE"] = true 3 | using Pkg 4 | Pkg.activate("PiCLES/") 5 | 6 | 7 | import Plots as plt 8 | using Setfield, IfElse 9 | 10 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 11 | 12 | import PiCLES: FetchRelations, ParticleTools 13 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 14 | using PiCLES.Operators: TimeSteppers 15 | using PiCLES.Simulations 16 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 17 | 18 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 19 | using PiCLES.Grids.CartesianGrid: TwoDCartesianGridMesh, TwoDCartesianGridStatistics 20 | 21 | using PiCLES.Models.WaveGrowthModels2D 22 | 23 | using Oceananigans.TimeSteppers: Clock, tick! 24 | import Oceananigans: fields 25 | using Oceananigans.Units 26 | import Oceananigans.Utils: prettytime 27 | 28 | using PiCLES.Architectures 29 | using PiCLES.Architectures: AbstractGridStatistics, CartesianGridStatistics 30 | 31 | using PiCLES.Operators.core_2D: ParticleDefaults as ParticleDefaults2D 32 | 33 | #using GLMakie 34 | using Plots 35 | 36 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 37 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 38 | 39 | using Revise 40 | 41 | using StaticArrays 42 | using StructArrays 43 | using BenchmarkTools 44 | 45 | using PiCLES.Grids 46 | 47 | using PiCLES.Operators.TimeSteppers: time_step! 48 | using DifferentialEquations 49 | using PiCLES.Operators: mapping_2D 50 | 51 | 52 | 53 | # %% 54 | 55 | Revise.retry() 56 | save_path = "plots/tests/S02_box_2D_mesh_grid/" 57 | mkpath(save_path) 58 | pwd() 59 | # % Parameters 60 | U10, V10 = 0.00, 00.0 61 | DT = 20minutes 62 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 63 | 64 | u(x, y, t) = IfElse.ifelse.(x .< 250e3, U10, 0.00) + y * 0.0 + t * 0.0 65 | v(x, y, t) = IfElse.ifelse.(x .< 250e3, V10, 0.00) + y * 0.0 + t * 0.0 .* cos(t * 5 / (1 * 60 * 60 * 2π)) 66 | 67 | # u(x, y, t) = U10 + x * 0.0 + y * 0.0 + t * 0.0 68 | # v(x, y, t) = V10 + x * 0.0 + y * 0.0 + t * 0.0 69 | winds = (u=u, v=v) 70 | 71 | grid = TwoDCartesianGridMesh(400e3, 41, 200e3, 21; periodic_boundary=(false, true)) 72 | heatmap(grid.data.x[:, 1], grid.data.y[1, :], transpose(grid.data.mask)) 73 | 74 | # %% 75 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q, 76 | propagation=true, 77 | input=false, 78 | dissipation=false, 79 | peak_shift=false, 80 | direction=false, 81 | ); 82 | 83 | default_ODE_parameters = (r_g=ODEpars.r_g, C_α=Const_Scg.C_alpha, 84 | C_φ=Const_ID.c_β, C_e=Const_ID.C_e, g=9.81);#, M=M); 85 | 86 | # define setting and standard initial conditions 87 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT); 88 | lne_local = round( log(WindSeamin["E"]) , digits=4) 89 | cg_u_local = round( WindSeamin["cg_bar_x"] , digits=4) 90 | cg_v_local = round(WindSeamin["cg_bar_y"], digits=4) 91 | 92 | ParticleMin = FetchRelations.MinimalParticle(2, 0, DT) 93 | # get_initial_windsea(2, 2, DT,particle_state=true ) 94 | 95 | ODE_settings = PW.ODESettings( 96 | Parameters=default_ODE_parameters, 97 | # define mininum energy threshold 98 | log_energy_minimum=ParticleMin[1], #log(FetchRelations.Eⱼ(0.1, DT)), 99 | #maximum energy threshold 100 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 101 | saving_step=DT, 102 | timestep=DT, 103 | total_time=T = 6days, 104 | adaptive=true, 105 | dt=1e-3, #60*10, 106 | dtmin=1e-4, #60*5, 107 | force_dtmin=true, 108 | callbacks=nothing, 109 | save_everystep=false) 110 | 111 | 112 | # %% 113 | function plot_particle_collection(wave_model) 114 | particles = wave_model.ParticleCollection 115 | p = plot(layout=(3, 2), size=(1200, 1100)) 116 | heatmap!(p, transpose(particles.on), subplot=1, title="on | iter=" * string(wave_model.clock.iteration)) 117 | heatmap!(p, transpose(particles.boundary), subplot=2, title="boundary") 118 | heatmap!(p, transpose(wave_model.State[:, :, 1]), subplot=3, title="State: Energy", clims=(0, NaN)) 119 | heatmap!(p, transpose(wave_model.State[:, :, 2]), subplot=4, title="State: x momentum ", clims=(0, NaN)) 120 | heatmap!(p, transpose(wave_model.State[:, :, 3]), subplot=6, title="State: y momentum ") 121 | # title = plot!(title="Plot title", grid=false, showaxis=false, bottom_margin=-50Plots.px) 122 | plot!(p, aspect_ratio=:equal) 123 | display(p) 124 | end 125 | 126 | 127 | # %% 128 | 129 | Revise.retry() 130 | 131 | default_windsea = FetchRelations.get_initial_windsea(2, 2, DT,particle_state=true ) 132 | # default_particle = ParticleDefaults(lne_local, cg_u_local, cg_v_local, 0.0, 0.0) 133 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; 134 | grid = grid, 135 | winds = winds, 136 | ODEsys = particle_system, 137 | ODEsets = ODE_settings, # ODE_settings 138 | #ODEinit_type=ParticleDefaults2D(default_windsea[1]*0.1, default_windsea[2]*0.1, default_windsea[3]*0.1, 0.0, 0.0), 139 | ODEinit_type=ParticleDefaults(ParticleMin), 140 | #ParticleDefaults2D(log(2), 0.0, 0.0, 0.0, 0.0), #"wind_sea", # default_ODE_valuves 141 | periodic_boundary= true, 142 | boundary_type= "same", 143 | #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), 144 | movie = true) 145 | 146 | #wave_model.ODEsettings.wind_min_squared = 0.0 147 | #wave_model.minimal_state = 2 * wave_model.minimal_state 148 | 149 | using PiCLES.Operators.mapping_2D: reset_PI_u!, ParticleToNode! 150 | 151 | # ### build Simulation 152 | wave_simulation = Simulation(wave_model, Δt=20minutes, stop_time=4hours)#1hours) 153 | initialize_simulation!(wave_simulation) 154 | # plot_particle_collection(wave_model) 155 | 156 | 157 | for PI in wave_simulation.model.ParticleCollection[5:15, 5:15] 158 | #reset_PI_u!(PI, ui= [ log( (5/4)^2) , 5.0 , 10.0, 0.0, 0.0]) 159 | reset_PI_u!(PI, ui= FetchRelations.get_initial_windsea(10.0, 12.0, 4hour, particle_state=true) ) 160 | ParticleToNode!(PI, wave_simulation.model.State, wave_simulation.model.grid, wave_simulation.model.periodic_boundary) 161 | end 162 | 163 | plot_particle_collection(wave_model) 164 | 165 | 166 | # %% Advance only 167 | wave_simulation.model.ParticleCollection[8, 8].ODEIntegrator.u 168 | wave_simulation.model.ParticleCollection[5, 2].ODEIntegrator.u 169 | 170 | FailedCollection = Vector{AbstractMarkedParticleInstance}([]) 171 | TimeSteppers.time_step!_advance(wave_simulation.model, wave_simulation.Δt, FailedCollection) 172 | 173 | wave_simulation.model.ParticleCollection[20, 12].ODEIntegrator.u 174 | wave_simulation.model.ParticleCollection[8, 8].ODEIntegrator.u 175 | wave_simulation.model.ParticleCollection[5, 2].ODEIntegrator.u 176 | 177 | 178 | TimeSteppers.time_step!_remesh(wave_simulation.model, wave_simulation.Δt) 179 | 180 | wave_simulation.model.ParticleCollection[20, 12].ODEIntegrator.u 181 | wave_simulation.model.ParticleCollection[8, 8].ODEIntegrator.u 182 | wave_simulation.model.ParticleCollection[5, 2].ODEIntegrator.u 183 | 184 | wave_simulation.model.State[5, 2, :] 185 | wave_simulation.model.State[:,:,1] 186 | 187 | #TimeSteppers.time_step!(wave_simulation.model, wave_simulation.Δt) 188 | 189 | 190 | # %% timstepper test 191 | Revise.retry() 192 | plot_particle_collection(wave_model) 193 | 194 | for i in 1:1:180 195 | TimeSteppers.time_step!(wave_simulation.model, wave_simulation.Δt) 196 | 197 | if i%8 == 0 198 | plot_particle_collection(wave_simulation.model) 199 | sleep(0.02) 200 | end 201 | wave_simulation.model.State[:, :, :] .= 0.0 202 | 203 | end 204 | 205 | 206 | # %% 207 | wave_simulation.model.ParticleCollection[20, 10] 208 | wave_simulation.model.ParticleCollection[20, 10].ODEIntegrator.u 209 | 210 | wave_simulation.model.grid.stats -------------------------------------------------------------------------------- /tests/T03_PIC_propagation_2d_land.jl: -------------------------------------------------------------------------------- 1 | ENV["JULIA_INCREMENTAL_COMPILE"] = true 2 | using Pkg 3 | Pkg.activate("PiCLES/") 4 | 5 | 6 | import Plots as plt 7 | using Setfield, IfElse 8 | 9 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 10 | 11 | import PiCLES: FetchRelations, ParticleTools 12 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 13 | using PiCLES.Operators: TimeSteppers 14 | using PiCLES.Simulations 15 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 16 | 17 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 18 | using PiCLES.Grids.CartesianGrid: TwoDCartesianGridMesh, ProjetionKernel, TwoDCartesianGridStatistics 19 | 20 | using PiCLES.Models.WaveGrowthModels2D 21 | 22 | using Oceananigans.TimeSteppers: Clock, tick! 23 | import Oceananigans: fields 24 | using Oceananigans.Units 25 | import Oceananigans.Utils: prettytime 26 | 27 | using PiCLES.Architectures 28 | using PiCLES.Architectures: AbstractGridStatistics, CartesianGridStatistics 29 | 30 | using PiCLES.Operators.core_2D: ParticleDefaults as ParticleDefaults2D 31 | 32 | #using GLMakie 33 | 34 | using Plots 35 | 36 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 37 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 38 | 39 | using Revise 40 | 41 | using StaticArrays 42 | using StructArrays 43 | using BenchmarkTools 44 | 45 | using PiCLES.Grids 46 | 47 | using PiCLES.Operators.TimeSteppers: time_step! 48 | using DifferentialEquations 49 | using PiCLES.Operators: mapping_2D 50 | 51 | 52 | 53 | # %% 54 | 55 | Revise.retry() 56 | save_path = "plots/tests/S02_box_2D_mesh_grid/" 57 | mkpath(save_path) 58 | pwd() 59 | # % Parameters 60 | U10, V10 = 15.0, -10.0 61 | DT = 20minutes 62 | 63 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 64 | 65 | 66 | u(x, y, t) = IfElse.ifelse.(x .< 250e3, U10, 0.00) + y * 0.0 + t * 0.0 67 | v(x, y, t) = IfElse.ifelse.(x .< 250e3, V10, 0.00) + y * 0.0 + t * 0.0 .* cos(t * 5 / (1 * 60 * 60 * 2π)) 68 | 69 | # u(x, y, t) = U10 + x * 0.0 + y * 0.0 + t * 0.0 70 | # v(x, y, t) = V10 + x * 0.0 + y * 0.0 + t * 0.0 71 | winds = (u=u, v=v) 72 | 73 | grid = TwoDCartesianGridMesh(400e3, 41, 200e3, 21, periodic_boundary=(false, true)) 74 | heatmap(grid.data.x[:, 1], grid.data.y[1, :], transpose(grid.data.mask)) 75 | 76 | # % Make fake mask 77 | mask = ones(Bool, size(grid.data.x)) # 1 is ocean, 0 is land (?) 78 | mask[10:20, 5:10] .= 0 79 | #mask = .!mask # to make one active block 80 | gridstats_mask = TwoDCartesianGridMesh(grid.stats; mask=mask) 81 | grid = TwoDCartesianGridMesh(gridstats_mask, grid.stats, ProjetionKernel) 82 | 83 | 84 | heatmap(grid.data.x[:,1], grid.data.y[1,:], transpose(grid.data.mask)) 85 | # heatmap(transpose(v.(grid.data.x, grid.data.y, 0))) 86 | 87 | # %% 88 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q, 89 | propagation=true, 90 | input=false, 91 | dissipation=false, 92 | peak_shift=false, 93 | direction=true, 94 | ); 95 | 96 | default_ODE_parameters = (r_g=ODEpars.r_g, C_α=Const_Scg.C_alpha, 97 | C_φ=Const_ID.c_β, C_e=Const_ID.C_e, g=9.81);#, M=M); 98 | 99 | # define setting and standard initial conditions 100 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT); 101 | lne_local = log(WindSeamin["E"]) 102 | cg_u_local = WindSeamin["cg_bar_x"] 103 | cg_v_local = WindSeamin["cg_bar_y"] 104 | 105 | ODE_settings = PW.ODESettings( 106 | Parameters=default_ODE_parameters, 107 | # define mininum energy threshold 108 | log_energy_minimum=lne_local,#log(FetchRelations.Eⱼ(0.1, DT)), 109 | #maximum energy threshold 110 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 111 | saving_step=DT, 112 | timestep=DT, 113 | total_time=T = 6days, 114 | adaptive=true, 115 | dt=1e-3, #60*10, 116 | dtmin=1e-4, #60*5, 117 | force_dtmin=true, 118 | callbacks=nothing, 119 | save_everystep=false) 120 | 121 | 122 | # %% 123 | 124 | function plot_particle_collection(wave_model) 125 | particles = wave_model.ParticleCollection 126 | p = plot(layout=(3, 2), size=(1200, 1000)) 127 | heatmap!(p, transpose(particles.on), subplot=1, title="on | iter=" * string(wave_model.clock.iteration)) 128 | heatmap!(p, transpose(particles.boundary), subplot=2, title="boundary") 129 | heatmap!(p, transpose(wave_model.State[:, :, 1]), subplot=3, title="State: Energy", clims=(0, NaN)) 130 | heatmap!(p, transpose(wave_model.State[:, :, 2]), subplot=4, title="State: x momentum ", clims=(0, NaN)) 131 | heatmap!(p, transpose(wave_model.State[:, :, 3]), subplot=6, title="State: y momentum ") 132 | # title = plot!(title="Plot title", grid=false, showaxis=false, bottom_margin=-50Plots.px) 133 | display(p) 134 | end 135 | 136 | # %% 137 | 138 | Revise.retry() 139 | 140 | default_windsea = FetchRelations.get_initial_windsea(U10, V10, DT,particle_state=true ) 141 | default_particle = ParticleDefaults(lne_local, cg_u_local, cg_v_local, 0.0, 0.0) 142 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 143 | winds=winds, 144 | ODEsys=particle_system, 145 | ODEsets=ODE_settings, # ODE_settings 146 | ODEinit_type=ParticleDefaults2D(default_windsea[1], default_windsea[2], default_windsea[3], 0.0, 0.0), 147 | #ParticleDefaults2D(log(2), 0.0, 0.0, 0.0, 0.0), #"wind_sea", # default_ODE_valuves 148 | periodic_boundary=true, 149 | boundary_type="same", 150 | #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), 151 | movie=true) 152 | 153 | #wave_model.ODEsettings.wind_min_squared = 0.0 154 | #wave_model.minimal_state = 2 * wave_model.minimal_state 155 | 156 | # ### build Simulation 157 | wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=4hours)#1hours) 158 | initialize_simulation!(wave_simulation) 159 | plot_particle_collection(wave_model) 160 | 161 | # %% Single Adance step 162 | PI = wave_simulation.model.ParticleCollection[2,1] 163 | step!(PI.ODEIntegrator, DT, true) 164 | 165 | model = wave_simulation.model 166 | mapping_2D.advance!(PI, model.State, FailedCollection, 167 | model.grid, model.winds, wave_simulation.Δt, 168 | model.ODEsettings.log_energy_maximum, 169 | model.ODEsettings.wind_min_squared, 170 | model.periodic_boundary, 171 | model.ODEdefaults) 172 | 173 | 174 | # %% Adance only test 175 | model = wave_simulation.model 176 | FailedCollection = Vector{AbstractMarkedParticleInstance}([]) 177 | for a_particle in model.ParticleCollection[findall(model.grid.data.mask .== 1)] 178 | @info a_particle.position_ij 179 | mapping_2D.advance!(a_particle, model.State, FailedCollection, 180 | model.grid, model.winds, wave_simulation.Δt, 181 | model.ODEsettings.log_energy_maximum, 182 | model.ODEsettings.wind_min_squared, 183 | model.periodic_boundary, 184 | model.ODEdefaults) 185 | 186 | # ParticleToNode!(a_particle, model.State, model.grid, model.periodic_boundary) 187 | 188 | plot_particle_collection(model) 189 | 190 | sleep(0.001) 191 | end 192 | 193 | 194 | 195 | # %% timstepper test 196 | 197 | Revise.retry() 198 | plot_particle_collection(wave_model) 199 | 200 | for i in 1:1:180 201 | TimeSteppers.time_step!(wave_simulation.model, wave_simulation.Δt) 202 | 203 | if i%8 == 0 204 | plot_particle_collection(wave_simulation.model) 205 | sleep(0.4) 206 | end 207 | wave_simulation.model.State[:, :, :] .= 0.0 208 | 209 | end 210 | 211 | -------------------------------------------------------------------------------- /tests/T04_2D_box_diagonal_BC.jl: -------------------------------------------------------------------------------- 1 | #ENV["JULIA_INCREMENTAL_COMPILE"] = true 2 | 3 | using Pkg 4 | Pkg.activate("PiCLES/") 5 | 6 | using Pkg 7 | Pkg.activate(".") 8 | 9 | #using Plots 10 | import Plots as plt 11 | using Setfield, IfElse 12 | 13 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 14 | 15 | import PiCLES: FetchRelations, ParticleTools 16 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 17 | using PiCLES.Operators: TimeSteppers 18 | using PiCLES.Simulations 19 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 20 | 21 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 22 | using PiCLES.Models.WaveGrowthModels2D 23 | 24 | using Oceananigans.TimeSteppers: Clock, tick! 25 | import Oceananigans: fields 26 | using Oceananigans.Units 27 | import Oceananigans.Utils: prettytime 28 | 29 | using PiCLES.Architectures 30 | using GLMakie 31 | 32 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 33 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 34 | 35 | using Revise 36 | 37 | # debugging: 38 | #using ProfileView 39 | 40 | # %% 41 | save_path = "plots/tests/T04_box_2_BC/" 42 | mkpath(save_path) 43 | 44 | # % Parameters 45 | U10, V10 = 10.0, 10.0 46 | dt_ODE_save = 30minutes 47 | DT = 30minutes 48 | # version 3 49 | r_g0 = 0.85 50 | 51 | # function to define constants 52 | 53 | 54 | # Const_Scg = PW.get_Scg_constants(C_alpha=-1.41, C_varphi=1.81e-5) 55 | 56 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 57 | 58 | u_func(x, y, t) = U10 #* sin(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) 59 | v_func(x, y, t) = V10 #* cos(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) 60 | # u_std = 2e3 * 1 61 | # v_std = 2e3 * 1 62 | # 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π)) 63 | # 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π)) 64 | 65 | # u_func(x, y, t) = 0.1 + IfElse.ifelse.( sin(t * 6 / (1 * 60 * 60 * 2π)) > 0 , 66 | # sin(t * 6 / (1 * 60 * 60 * 2π)) *U10 * exp(-(x - 5e3)^2 / u_std^2) * exp(-(y - 5e3)^2 / v_std^2), 67 | # 0.1) 68 | # v_func(x, y, t) = 0.1 + IfElse.ifelse.(sin(t * 3 / (1 * 60 * 60 * 2π)) > 0, 69 | # 0.0, 70 | # -0.0) 71 | 72 | # u_func(x, y, t) = IfElse.ifelse.(x .< 5e3, U10, 0.2) + y * 0 + t * 0 73 | # v_func(x, y, t) = (IfElse.ifelse.(x .< 5e3, V10, 0.2) + y * 0) .* cos(t * 3 / (1 * 60 * 60 * 2π)) 74 | 75 | # this shuold hopefully work 76 | # u(x, y, t) = x * 0 + y * 0 + t * 0/ DT + 5.0 77 | # v(x, y, t) = x * 0 + y * 0 + t * 0/ DT + 10.0 78 | 79 | u(x, y, t) = u_func(x, y, t) 80 | v(x, y, t) = v_func(x, y, t) 81 | winds = (u=u, v=v) 82 | 83 | typeof(winds.u) 84 | typeof(winds.u(1e3, 1e3, 11)) 85 | #typeof(u_func(1e3, 1e3, 11)) 86 | #typeof(winds.u(x,y,t)) 87 | 88 | # u2 = winds.u(x, y, t) 89 | # typeof(u2) 90 | # typeof(winds.u(x, y, t)) 91 | # %% 92 | 93 | grid = TwoDGrid(100e3, 51, 100e3, 51) 94 | mesh = TwoDGridMesh(grid, skip=1); 95 | gn = TwoDGridNotes(grid); 96 | 97 | #heatmap( v.(mesh.x, mesh.y, 0) ) 98 | 99 | 100 | Revise.retry() 101 | 102 | # define variables based on particle equation 103 | 104 | #ProfileView.@profview 105 | #ProfileView.@profview 106 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q, input=true, dissipation=true); 107 | #particle_equations = PW3.particle_equations_vec5(u, v, u, v, γ=Const_ID.γ, q=Const_ID.q); 108 | 109 | # define V4 parameters absed on Const NamedTuple: 110 | default_ODE_parameters = (r_g=r_g0, C_α=Const_Scg.C_alpha, 111 | C_φ=Const_ID.c_β, C_e=Const_ID.C_e, g=9.81); 112 | 113 | # define setting and standard initial conditions 114 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT); 115 | #WindSeamin = FetchRelations.MinimalWindsea(u(0, 0, 0), v(0, 0, 0), DT / 2) 116 | #WindSeamin = FetchRelations.get_initial_windsea(u(0, 0, 0), v(0, 0, 0), DT/5) 117 | lne_local = log(WindSeamin["E"]) 118 | cg_u_local = WindSeamin["cg_bar_x"] 119 | cg_v_local = WindSeamin["cg_bar_y"] 120 | 121 | ODE_settings = PW.ODESettings( 122 | Parameters=default_ODE_parameters, 123 | # define mininum energy threshold 124 | log_energy_minimum=lne_local,#log(FetchRelations.Eⱼ(0.1, DT)), 125 | #maximum energy threshold 126 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 127 | saving_step=dt_ODE_save, 128 | timestep=DT, 129 | total_time=T = 6days, 130 | adaptive=true, 131 | dt=1e-3, #60*10, 132 | dtmin=1e-4, #60*5, 133 | force_dtmin=true, 134 | callbacks=nothing, 135 | save_everystep=false) 136 | 137 | 138 | default_particle = ParticleDefaults(lne_local, cg_u_local, cg_v_local, 0.0, 0.0) 139 | 140 | 141 | # plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(u.(mesh.x, mesh.y, 0))) 142 | 143 | # plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(v.(mesh.x, mesh.y, 0))) 144 | # %% build model 145 | Revise.retry() 146 | 147 | 148 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 149 | winds=winds, 150 | ODEsys=particle_system, 151 | ODEsets=ODE_settings, # ODE_settings 152 | ODEinit_type="wind_sea", # default_ODE_parameters 153 | periodic_boundary=false, 154 | boundary_type="same", 155 | #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), 156 | movie=true) 157 | 158 | 159 | ### build Simulation 160 | #wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=4hours)#1hours) 161 | wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=6hour)#1hours) 162 | initialize_simulation!(wave_simulation) 163 | 164 | 165 | #init_state_store!(wave_simulation, save_path) 166 | #wave_simulation.model.MovieState = wave_simulation.model.State 167 | 168 | @time run!(wave_simulation, cash_store=true, debug=true) 169 | #reset_simulation!(wave_simulation) 170 | # run simulation 171 | #ProfileView.@profview run!(wave_simulation, cash_store=true, debug=true) 172 | 173 | 174 | istate = wave_simulation.store.store[end]; 175 | p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, istate[:, :, 1]) 176 | 177 | -------------------------------------------------------------------------------- /tests/T04_2D_box_rotation.jl: -------------------------------------------------------------------------------- 1 | ENV["JULIA_INCREMENTAL_COMPILE"]=true 2 | 3 | import Plots as plt 4 | using Setfield, IfElse 5 | 6 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 7 | 8 | 9 | import PiCLES: FetchRelations, ParticleTools 10 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 11 | using PiCLES.Operators: TimeSteppers 12 | using PiCLES.Simulations 13 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 14 | 15 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 16 | using PiCLES.Models.WaveGrowthModels2D 17 | 18 | using Oceananigans.TimeSteppers: Clock, tick! 19 | import Oceananigans: fields 20 | using Oceananigans.Units 21 | import Oceananigans.Utils: prettytime 22 | 23 | using PiCLES.Architectures 24 | using GLMakie 25 | 26 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 27 | using PiCLES.Plotting.movie: init_movie_2D_box_plot, init_movie_2D_box_plot_small 28 | 29 | # debugging: 30 | #using ProfileView 31 | 32 | # %% 33 | save_path = "plots/tests/T04_box_2d/" 34 | mkpath(save_path) 35 | 36 | # % Parameters 37 | U10,V10 = 10.0, 10.0 38 | dt_ODE_save = 30minutes 39 | DT = 20minutes 40 | # version 3 41 | 42 | 43 | # function to define constants 44 | # ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 45 | # Const_ID 46 | 47 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 48 | 49 | # u(x, y, t) = 0.01 + U10 * sin(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) 50 | # v(x, y, t) = 0.01 - V10 * cos(t / (6*60*60 * 2π) ) * sin(x / 50e3) * sin(y / 50e3) 51 | u_std= 20e3 *1 52 | v_std= 20e3 *1 53 | center = 25e3 54 | u_func(x, y, t) = U10 * exp(-(x - center)^2 / u_std^2) * exp(-(y - center)^2 / v_std^2) * cos(t * 1.2 / (1 * 60 * 60 * 2π)) 55 | v_func(x, y, t) = V10 * exp(-(x - center)^2 / u_std^2) * exp(-(y - center)^2 / v_std^2) * sin(t * 1.2 / (1 * 60 * 60 * 2π)) 56 | 57 | # u_func(x, y, t) = 0.1 + IfElse.ifelse.( sin(t * 3 / (1 * 60 * 60 * 2π)) > 0 , 58 | # sin(t * 3 / (1 * 60 * 60 * 2π)) *U10 * exp(-(x - 5e3)^2 / u_std^2) * exp(-(y - 5e3)^2 / v_std^2), 59 | # 0.0) 60 | # v_func(x, y, t) = 0.1 + IfElse.ifelse.(sin(t * 3 / (1 * 60 * 60 * 2π)) > 0, 61 | # sin(t * 3 / (1 * 60 * 60 * 2π)) * U10 * exp(-(x - 5e3)^2 / u_std^2) * exp(-(y - 5e3)^2 / v_std^2), 62 | # 0.0) 63 | 64 | #t, x, y, c̄_x, c̄_y, lne, Δn, Δφ_p, r_g, C_α, C_φ, g, C_e = vars = PW.init_vars(); 65 | 66 | # u_func(x, y, t) = IfElse.ifelse.(x .< 5e3, U10, 0.2) + y * 0 + t * 0 67 | # v_func(x, y, t) = (IfElse.ifelse.(x .< 5e3, V10, 0.2) + y * 0) .* cos(t * 3 / (1 * 60 * 60 * 2π)) 68 | 69 | # this shuold hopefully work 70 | # u(x, y, t) = x * 0 + y * 0 + t * 0/ DT + 5.0 71 | # v(x, y, t) = x * 0 + y * 0 + t * 0/ DT + 10.0 72 | 73 | u(x, y, t) = u_func(x, y, t) 74 | v(x, y, t) = v_func(x, y, t) 75 | winds = (u=u, v=v) 76 | 77 | 78 | grid = TwoDGrid(100e3, 81, 100e3, 81) 79 | mesh = TwoDGridMesh(grid, skip=1); 80 | gn = TwoDGridNotes(grid); 81 | 82 | Revise.retry() 83 | # define variables based on particle equation 84 | 85 | #ProfileView.@profview 86 | #ProfileView.@profview 87 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q, input=true, dissipation=true); 88 | #particle_equations = PW3.particle_equations_vec5(u, v, u, v, γ=Const_ID.γ, q=Const_ID.q); 89 | 90 | 91 | # define setting and standard initial conditions 92 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ) 93 | #WindSeamin = FetchRelations.MinimalWindsea(u(0, 0, 0), v(0, 0, 0), DT / 2) 94 | #WindSeamin = FetchRelations.get_initial_windsea(u(0, 0, 0), v(0, 0, 0), DT/5) 95 | lne_local = log(WindSeamin["E"]) 96 | default_particle = ParticleDefaults(lne_local, WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0) 97 | 98 | ODE_settings = PW.ODESettings( 99 | Parameters=ODEpars, 100 | # define mininum energy threshold 101 | log_energy_minimum=lne_local,#log(FetchRelations.Eⱼ(0.1, DT)), 102 | #maximum energy threshold 103 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 104 | saving_step=dt_ODE_save, 105 | timestep=DT, 106 | total_time=T=12days, 107 | adaptive=true, 108 | dt=1e-3, #60*10, 109 | dtmin=1e-4, #60*5, 110 | force_dtmin=true, 111 | callbacks=nothing, 112 | save_everystep=false) 113 | 114 | 115 | 116 | # %% 117 | Revise.retry() 118 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 119 | winds=winds, 120 | ODEsys=particle_system, 121 | ODEsets=ODE_settings, # ODE_settings 122 | ODEinit_type="wind_sea", # default_ODE_parameters 123 | periodic_boundary=false, 124 | boundary_type="same", 125 | # minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), # 126 | # minimal_state=FetchRelations.MinimalState(2, 2, DT) * 1, 127 | movie=true) 128 | 129 | 130 | wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=24hours)#1hours) 131 | initialize_simulation!(wave_simulation) 132 | 133 | #reset_simulation!(wave_simulation, particle_initials=copy(wave_model.ODEdefaults)) 134 | 135 | Revise.retry() 136 | #using PiCLES.Plotting.movie: init_movie_2D_box_plot 137 | fig, n = init_movie_2D_box_plot_small(wave_simulation, name_string="Rotating Stationary Winds") 138 | 139 | #wave_simulation.stop_time += 1hour 140 | N = 60 *8 141 | record(fig, save_path*"T02_2D_totating_winds_nonper_small.gif", 1:N, framerate=10) do i 142 | @info "Plotting frame $i of $N..." 143 | #@time for _ = 1:10 144 | #run!(wave_simulation, store=false) 145 | @info wave_simulation.model.clock 146 | movie_time_step!(wave_simulation.model, wave_simulation.Δt) 147 | #end 148 | n[] = 1 149 | end 150 | -------------------------------------------------------------------------------- /tests/T04_2D_on_off_particle_tests.jl: -------------------------------------------------------------------------------- 1 | 2 | #using Plots 3 | import Plots as plt 4 | using Setfield, IfElse 5 | 6 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 7 | 8 | import PiCLES: FetchRelations, ParticleTools 9 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 10 | using PiCLES.Operators: TimeSteppers 11 | using PiCLES.Simulations 12 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 13 | 14 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 15 | using PiCLES.Models.WaveGrowthModels2D 16 | 17 | using Oceananigans.TimeSteppers: Clock, tick! 18 | import Oceananigans: fields 19 | using Oceananigans.Units 20 | import Oceananigans.Utils: prettytime 21 | 22 | using PiCLES.Architectures 23 | using GLMakie 24 | 25 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 26 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 27 | 28 | # %% 29 | 30 | 31 | save_path = "plots/tests/T04_2D_particle_on_off/" 32 | mkpath(save_path) 33 | 34 | ##### basic parameters 35 | # timestep 36 | DT = 20minutes 37 | # Characterstic wind velocities and std 38 | U10, V10 = 10.0, 10.0 39 | 40 | # Define basic ODE parameters 41 | r_g0 = 0.85 42 | Const_ID = PW4.get_I_D_constant() 43 | 44 | Const_Scg = PW4.get_Scg_constants(C_alpha=-1.41, C_varphi=1.81e-5) 45 | 46 | 47 | # define grid 48 | grid = TwoDGrid(100e3, 21, 50e3, 11) 49 | mesh = TwoDGridMesh(grid, skip=1); 50 | gn = TwoDGridNotes(grid); 51 | 52 | # example user function 53 | u_func(x, y, t) = U10 + x * 0 + y * 0 + t * 0 54 | v_func(x, y, t) = V10 + x * 0 + y * 0 + t * 0 55 | 56 | # provide function handles for ODE and Simulation in the right format 57 | u(x, y, t) = u_func(x, y, t) 58 | v(x, y, t) = v_func(x, y, t) 59 | winds = (u=u, v=v) 60 | 61 | 62 | # define ODE system and parameters 63 | Revise.retry() 64 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q); 65 | 66 | 67 | default_ODE_parameters = (r_g=r_g0, C_α=Const_Scg.C_alpha, 68 | C_φ=Const_ID.c_β, C_e=Const_ID.C_e, g=9.81) 69 | 70 | 71 | Revise.retry() 72 | # Default initial conditions based on timestep and chaeracteristic wind velocity 73 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT) 74 | default_particle = ParticleDefaults(WindSeamin["lne"], WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0) 75 | 76 | # ... and ODESettings 77 | ODE_settings = PW.ODESettings( 78 | Parameters=default_ODE_parameters, 79 | # define mininum energy threshold 80 | log_energy_minimum=WindSeamin["lne"], 81 | #maximum energy threshold 82 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 83 | # define minimum wind squared threshold 84 | wind_min_squared=2.0, 85 | saving_step=DT, 86 | timestep=DT, 87 | total_time=T = 6days, 88 | adaptive=true, 89 | dt=1e-3, #60*10, 90 | dtmin=1e-4, #60*5, 91 | force_dtmin=true, 92 | callbacks=nothing, 93 | save_everystep=false) 94 | 95 | 96 | # %% half domain tests 97 | Revise.retry() 98 | #gridmesh = [(i, j) for i in [-10,10], j in [0]] 99 | #gridmesh = [(i, j) for i in [10], j in [0]] 100 | 101 | U10 = -8 102 | V10 = 0.0 103 | 104 | @show U10, V10 105 | 106 | x0 =50e3 107 | Lx = (gn.Nx - 1) * gn.dx 108 | # u_func(x, y, t) = IfElse.ifelse.(x .< x0, U10, U10 * (1 -x/Lx) ) + y * 0 + t * 0 109 | # v_func(x, y, t) = IfElse.ifelse.(x .< x0, V10, V10 * (1 -x/Lx) ) + y * 0 + t * 0 110 | 111 | u_func(x, y, t) = IfElse.ifelse.(x .< x0, x*0+ 0, U10 * (x - x0) / (Lx-x0)) + y * 0 + t * 0 112 | v_func(x, y, t) = IfElse.ifelse.(x .< x0, x*0+ 0, V10 * (x - x0) / (Lx-x0)) + y * 0 + t * 0 113 | 114 | # u_func(x, y, t) = IfElse.ifelse.(x .< x0, x *0+ 0.0 , U10 ) + y * 0 + t * 0 115 | # v_func(x, y, t) = IfElse.ifelse.(x .< x0, x *0 + 0.0 , V10 ) + y * 0 + t * 0 116 | u(x, y, t) = u_func(x, y, t) 117 | v(x, y, t) = v_func(x, y, t) 118 | winds = (u=u, v=v) 119 | 120 | #winds, u, v =convert_wind_field_functions(u_func, v_func, x, y, t) 121 | Revise.retry() 122 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q) 123 | 124 | 125 | 126 | # Define wave model 127 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 128 | winds=winds, 129 | ODEsys=particle_system, 130 | ODEsets=ODE_settings, # ODE_settings 131 | ODEinit_type="wind_sea", # default_ODE_parameters 132 | periodic_boundary=false, 133 | boundary_type="same", 134 | minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), # 135 | minimal_state=FetchRelations.MinimalState(2, 2, DT) * 1, 136 | movie=true) 137 | 138 | typeof(wave_model) 139 | 140 | 141 | # %% 142 | ### build Simulation 143 | Revise.retry() 144 | wave_simulation = Simulation(wave_model, Δt=DT/2, stop_time=4hours) 145 | initialize_simulation!(wave_simulation) 146 | 147 | init_state_store!(wave_simulation, save_path) 148 | 149 | length(wave_simulation.store.shape) 150 | 151 | #run!(wave_simulation, cash_store=true, debug=true) 152 | run!(wave_simulation, store=true, cash_store=false, debug=false) 153 | 154 | close_store!(wave_simulation) 155 | 156 | #run!(wave_simulation, cash_store=true, debug=true) 157 | # % 158 | 159 | # plot(wave_simulation.model.State[:,:,2]) 160 | # wave_simulation.model.State[:, :, 2] 161 | # # wave_simulation.model.State[:, :, 1] 162 | # time_step!(wave_simulation.model, wave_simulation.Δt) 163 | 164 | # wave_simulation.model.State[:, :, 2] 165 | 166 | # (wave_simulation.model.State[:, :, 1] .>= wave_model.minimal_state[1]) 167 | 168 | # (wave_simulation.model.State[:, :, 2] .>= wave_model.minimal_state[2]) 169 | 170 | # wave_simulation.model.State[:, :, 2] 171 | # wave_simulation.model.State[:, :, 3] 172 | 173 | 174 | # % 175 | # or, alternatively, make movie 176 | plot_name="T02_2D_growing_U" * string(U10) * "_V" * string(V10) 177 | N=80 178 | axline=x0/1e3 179 | fig, n = init_movie_2D_box_plot(wave_simulation; resolution=(1300, 800), name_string=plot_name, aspect=3, axline=axline) 180 | 181 | #wave_simulation.stop_time += 1hour 182 | #N = 36 183 | #plot_name = "dummy" 184 | 185 | record(fig, save_path * plot_name * ".gif", 1:N, framerate=10) do i 186 | @info "Plotting frame $i of $N..." 187 | @info wave_simulation.model.clock 188 | movie_time_step!(wave_simulation.model, wave_simulation.Δt) 189 | n[] = 1 190 | end 191 | 192 | # %% 193 | #wave_simulation.model.State[:, :, 2] 194 | #test particle equations 195 | #using BenchmarkTools 196 | using Profile 197 | 198 | Revise.retry() 199 | tt = [(i, j) for i in [-1,0, 1], j in [-1, 0, 1]] 200 | for (i,j) in tt 201 | #@show PW4.speed(i,j) 202 | #@time PW4.α_func(i,j) 203 | @show i,j, PW4.sin2_a_min_b( 1, 1 , i,j) 204 | end 205 | 206 | PW4.sin2_a_min_b( 1, 1 , 0.01,0.01 ) 207 | PW4.sin2_a_min_b( 0,0.1 , 0,0.1 ) 208 | PW4.sin2_a_min_b( 0,0 , 1,1 ) 209 | PW4.sin2_a_min_b( 1,0 , 0,1 ) 210 | PW4.sin2_a_min_b( 0,1 , 0,1 ) 211 | 212 | PW4.sin2_a_min_b( 0,1 , 0,0 ) 213 | 214 | 215 | PW4.αₚ(0,0,0,0) 216 | -------------------------------------------------------------------------------- /tests/T04_2D_reg_test.jl: -------------------------------------------------------------------------------- 1 | #using Plots 2 | 3 | using Pkg 4 | Pkg.activate("PiCLES/") 5 | 6 | import Plots as plt 7 | using Setfield, IfElse 8 | 9 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 10 | 11 | import PiCLES: FetchRelations, ParticleTools 12 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 13 | using PiCLES.Operators: TimeSteppers 14 | using PiCLES.Simulations 15 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 16 | 17 | # using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 18 | using PiCLES.Grids.CartesianGrid: TwoDCartesianGridMesh, TwoDCartesianGridStatistics 19 | using PiCLES.Models.WaveGrowthModels2D 20 | 21 | using Oceananigans.TimeSteppers: Clock, tick! 22 | import Oceananigans: fields 23 | using Oceananigans.Units 24 | import Oceananigans.Utils: prettytime 25 | 26 | using PiCLES.Architectures 27 | using GLMakie 28 | 29 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 30 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 31 | 32 | 33 | # %% 34 | save_path = "plots/tests/T04_2D_regtest/" 35 | mkpath(save_path) 36 | 37 | ##### basic parameters 38 | 39 | # timestep 40 | DT = 10minutes 41 | # Characterstic wind velocities and std 42 | U10, V10 = 5.0, 5.0 43 | 44 | # Define basic ODE parameters 45 | 46 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 47 | 48 | # define grid 49 | grid = TwoDCartesianGridMesh(120e3, 31, 120e3, 31) 50 | 51 | # example user function 52 | u_func(x, y, t) = U10 + x * 0 + y * 0 + t * 0 53 | v_func(x, y, t) = V10 + x * 0 + y * 0 + t * 0 54 | 55 | # provide function handles for ODE and Simulation in the right format 56 | u(x, y, t) = u_func(x, y, t) 57 | v(x, y, t) = v_func(x, y, t) 58 | winds = (u=u, v=v) 59 | 60 | 61 | # define ODE system and parameters 62 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q); 63 | 64 | default_ODE_parameters = (r_g=0.85, C_α=Const_Scg.C_alpha, 65 | C_φ=Const_ID.c_β, C_e=Const_ID.C_e, g=9.81) 66 | 67 | Revise.retry() 68 | # Default initial conditions based on timestep and chaeracteristic wind velocity 69 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT ) 70 | default_particle = ParticleDefaults(WindSeamin["lne"], WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0) 71 | 72 | # ... and ODESettings 73 | ODE_settings = PW.ODESettings( 74 | Parameters=default_ODE_parameters, 75 | # define mininum energy threshold 76 | log_energy_minimum=WindSeamin["lne"], 77 | #maximum energy threshold 78 | log_energy_maximum=log(17),#log(17), # correcsponds to Hs about 16 m 79 | saving_step=DT, 80 | timestep=DT, 81 | total_time=T=6days, 82 | adaptive=true, 83 | dt=1e-3, #60*10, 84 | dtmin=1e-4, #60*5, 85 | force_dtmin=true, 86 | callbacks=nothing, 87 | save_everystep=false) 88 | 89 | 90 | 91 | # %% 92 | function make_reg_test(wave_model, save_path; plot_name="dummy", N=36) 93 | 94 | ### build Simulation 95 | wave_simulation = Simulation(wave_model, Δt=DT, stop_time=1hour)#1hours) 96 | initialize_simulation!(wave_simulation) 97 | 98 | # run simulation 99 | #run!(wave_simulation, cash_store=true, debug=true) 100 | # or, alternatively, make movie 101 | 102 | fig, n = init_movie_2D_box_plot(wave_simulation) 103 | 104 | #wave_simulation.stop_time += 1hour 105 | #N = 36 106 | #plot_name = "dummy" 107 | record(fig, save_path * plot_name * ".gif", 1:N, framerate=10) do i 108 | @info "Plotting frame $i of $N..." 109 | @info wave_simulation.model.clock 110 | movie_time_step!(wave_simulation.model, wave_simulation.Δt) 111 | 112 | n[] = 1 113 | end 114 | 115 | end 116 | 117 | # %% 118 | Revise.retry() 119 | 120 | # loop over U10 and V10 range 121 | # gridmesh = [(i, j, per) for i in -10:10:10, j in -10:10:10, per in [false, true]] 122 | gridmesh = [(i, j, per) for i in -10:10:10, j in -10:10:10, per in [true, false]] 123 | 124 | #for I in CartesianIndices(gridmesh) 125 | for (U10, V10, per) in gridmesh 126 | periodic = per# == true 127 | @show U10, V10, periodic 128 | 129 | u_func(x, y, t) = U10 + x * 0 + y * 0 + t * 0 #+ sign.(rand(-1:1)) .* 0.1 130 | v_func(x, y, t) = V10 + x * 0 + y * 0 + t * 0 #+ sign.(rand(-1:1)) .* 0.1 131 | u(x, y, t) = u_func(x, y, t) 132 | v(x, y, t) = v_func(x, y, t) 133 | winds = (u=u, v=v) 134 | 135 | #winds, u, v =convert_wind_field_functions(u_func, v_func, x, y, t) 136 | 137 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q) 138 | 139 | ## Define wave model 140 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 141 | winds=winds, 142 | ODEsys=particle_system, 143 | ODEsets=ODE_settings, # ODE_settings 144 | ODEinit_type="wind_sea", # default_ODE_parameters 145 | periodic_boundary=periodic, 146 | boundary_type="same", 147 | minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), # 148 | movie=true) 149 | 150 | make_reg_test(wave_model, save_path, plot_name="T02_2D_periodic"*string(periodic)*"_U"*string(U10)*"_V"*string(V10)) 151 | end 152 | 153 | 154 | # %% half domain tests 155 | gridmesh = [(i, j, per) for i in -10:10:10, j in -10:10:10, per in [true, false]] 156 | #for I in CartesianIndices(gridmesh) 157 | for (U10, V10, per) in gridmesh 158 | periodic = per == true 159 | @show U10, V10, periodic 160 | 161 | # u_func(x, y, t) = U10 + x * 0 + y * 0 + t * 0 + sign.(rand(-1:1)) .* 0.1 162 | # v_func(x, y, t) = V10 + x * 0 + y * 0 + t * 0 + sign.(rand(-1:1)) .* 0.1 163 | 164 | # u_func(x, y, t) = IfElse.ifelse.(x .<60e3, U10, sign.(rand(-1:1)) .* 0.1) + y * 0 + t * 0 165 | # v_func(x, y, t) = (IfElse.ifelse.(x .< 60e3, V10, sign.(rand(-1:1)) .* 0.1) + y * 0) .* cos(t * 3 / (1 * 60 * 60 * 2π)) 166 | u_func(x, y, t) = IfElse.ifelse.(x .< 60e3, U10, 0.0) + y * 0 + t * 0 167 | v_func(x, y, t) = (IfElse.ifelse.(x .< 60e3, V10, 0.0) + y * 0) .* cos(t * 3 / (1 * 60 * 60 * 2π)) 168 | 169 | u(x, y, t) = u_func(x, y, t) 170 | v(x, y, t) = v_func(x, y, t) 171 | winds = (u=u, v=v) 172 | 173 | #winds, u, v =convert_wind_field_functions(u_func, v_func, x, y, t) 174 | 175 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q) 176 | 177 | ## Define wave model 178 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 179 | winds=winds, 180 | ODEsys=particle_system, 181 | ODEsets=ODE_settings, # ODE_settings 182 | ODEinit_type="wind_sea", # default_ODE_parameters 183 | periodic_boundary=periodic, 184 | boundary_type="same", 185 | minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), # 186 | movie=true) 187 | 188 | make_reg_test(wave_model, save_path, plot_name="T02_2D_hald_domain_periodic" * string(periodic) * "_U" * string(U10) * "_V" * string(V10), N= 72) 189 | end 190 | -------------------------------------------------------------------------------- /tests/T04_2D_reg_test_large_grid.jl: -------------------------------------------------------------------------------- 1 | 2 | 3 | #using Plots 4 | import Plots as plt 5 | using Setfield, IfElse 6 | 7 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 8 | 9 | import PiCLES: FetchRelations, ParticleTools 10 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 11 | using PiCLES.Operators: TimeSteppers 12 | using PiCLES.Simulations 13 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 14 | 15 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 16 | using PiCLES.Models.WaveGrowthModels2D 17 | 18 | using Oceananigans.TimeSteppers: Clock, tick! 19 | import Oceananigans: fields 20 | using Oceananigans.Units 21 | import Oceananigans.Utils: prettytime 22 | 23 | using PiCLES.Architectures 24 | using GLMakie 25 | 26 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 27 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 28 | 29 | # %% 30 | 31 | save_path = "plots/tests/T04_2D_regtest_largr_grid/" 32 | mkpath(save_path) 33 | 34 | ##### basic parameters 35 | 36 | # timestep 37 | DT = 20minutes 38 | # Characterstic wind velocities and std 39 | U10, V10 = 10.0, 10.0 40 | 41 | # Define basic ODE parameters 42 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 43 | 44 | 45 | # define grid 46 | grid = TwoDGrid(200e3, 41, 200e3, 41) 47 | mesh = TwoDGridMesh(grid, skip=1); 48 | gn = TwoDGridNotes(grid); 49 | 50 | # example user function 51 | u_func(x, y, t) = U10 + x * 0 + y * 0 + t * 0 52 | v_func(x, y, t) = V10 + x * 0 + y * 0 + t * 0 53 | 54 | # provide function handles for ODE and Simulation in the right format 55 | u(x, y, t) = u_func(x, y, t) 56 | v(x, y, t) = v_func(x, y, t) 57 | winds = (u=u, v=v) 58 | 59 | 60 | # define ODE system and parameters 61 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q); 62 | 63 | 64 | 65 | Revise.retry() 66 | # Default initial conditions based on timestep and chaeracteristic wind velocity 67 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT) 68 | default_particle = ParticleDefaults(WindSeamin["lne"], WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0) 69 | 70 | # ... and ODESettings 71 | ODE_settings = PW.ODESettings( 72 | Parameters=ODEpars, 73 | # define mininum energy threshold 74 | log_energy_minimum=WindSeamin["lne"], 75 | #maximum energy threshold 76 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 77 | saving_step=DT, 78 | timestep=DT, 79 | total_time=T = 6days, 80 | adaptive=true, 81 | dt=1e-3, #60*10, 82 | dtmin=1e-4, #60*5, 83 | force_dtmin=true, 84 | callbacks=nothing, 85 | save_everystep=false) 86 | 87 | 88 | 89 | function make_reg_test(wave_model, save_path; plot_name="dummy", N=36) 90 | 91 | ### build Simulation 92 | wave_simulation = Simulation(wave_model, Δt=DT, stop_time=1hour)#1hours) 93 | initialize_simulation!(wave_simulation) 94 | 95 | # run simulation 96 | #run!(wave_simulation, cash_store=true, debug=true) 97 | # or, alternatively, make movie 98 | 99 | fig, n = init_movie_2D_box_plot(wave_simulation) 100 | 101 | #wave_simulation.stop_time += 1hour 102 | #N = 36 103 | #plot_name = "dummy" 104 | record(fig, save_path * plot_name * ".gif", 1:N, framerate=10) do i 105 | @info "Plotting frame $i of $N..." 106 | @info wave_simulation.model.clock 107 | movie_time_step!(wave_simulation.model, wave_simulation.Δt) 108 | 109 | n[] = 1 110 | end 111 | 112 | end 113 | 114 | # %% 115 | # # loop over U10 and V10 range 116 | # gridmesh = [(i, j, per) for i in -10:10:10, j in -10:10:10, per in [false, true]] 117 | # #for I in CartesianIndices(gridmesh) 118 | # for (U10, V10, per) in gridmesh 119 | # periodic = per == true 120 | # @show U10, V10, periodic 121 | 122 | # u_func(x, y, t) = U10 + x * 0 + y * 0 + t * 0 + sign.(rand(-1:1)) .* 0.1 123 | # v_func(x, y, t) = V10 + x * 0 + y * 0 + t * 0 + sign.(rand(-1:1)) .* 0.1 124 | # u(x, y, t) = u_func(x, y, t) 125 | # v(x, y, t) = v_func(x, y, t) 126 | # winds = (u=u, v=v) 127 | 128 | # #winds, u, v =convert_wind_field_functions(u_func, v_func, x, y, t) 129 | 130 | # particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q) 131 | 132 | 133 | # ## Define wave model 134 | # wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 135 | # winds=winds, 136 | # ODEsys=particle_system, 137 | # ODEvars=vars, 138 | # ODEsets=ODE_settings, # ODE_settings 139 | # ODEdefaults=default_particle, # default_ODE_parameters 140 | # minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), # 141 | # periodic_boundary=periodic, 142 | # boundary_type="wind_sea",#"zero",#"wind_sea", #"wind_sea", # or "default" 143 | # movie=true) 144 | 145 | # make_reg_test(wave_model, save_path, plot_name="T02_2D_periodic" * string(periodic) * "_U" * string(U10) * "_V" * string(V10)) 146 | # end 147 | Revise.retry() 148 | 149 | # %% half domain tests 150 | gridmesh = [(i, j, per) for i in -10:10:10, j in -10:10:10, per in [false, true]] 151 | #for I in CartesianIndices(gridmesh) 152 | for (U10, V10, per) in gridmesh 153 | periodic = per == true 154 | @show U10, V10, periodic 155 | 156 | # u_func(x, y, t) = U10 + x * 0 + y * 0 + t * 0 + sign.(rand(-1:1)) .* 0.1 157 | # v_func(x, y, t) = V10 + x * 0 + y * 0 + t * 0 + sign.(rand(-1:1)) .* 0.1 158 | 159 | u_func(x, y, t) = IfElse.ifelse.(x .< 100e3, U10, sign.(rand(-1:1)) .* 0.1) + y * 0 + t * 0 160 | v_func(x, y, t) = (IfElse.ifelse.(x .< 100e3, V10, sign.(rand(-1:1)) .* 0.1) + y * 0) .* cos(t * 3 / (1 * 60 * 60 * 2π)) 161 | u(x, y, t) = u_func(x, y, t) 162 | v(x, y, t) = v_func(x, y, t) 163 | winds = (u=u, v=v) 164 | 165 | #winds, u, v =convert_wind_field_functions(u_func, v_func, x, y, t) 166 | 167 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q) 168 | 169 | ## Define wave model 170 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 171 | winds=winds, 172 | ODEsys=particle_system, 173 | ODEsets=ODE_settings, # ODE_settings 174 | ODEinit_type="wind_sea", # default_ODE_parameters 175 | periodic_boundary=periodic, 176 | boundary_type="same", 177 | minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), # 178 | #minimal_state=FetchRelations.MinimalState(2, 2, DT) * 1, 179 | movie=true) 180 | 181 | 182 | make_reg_test(wave_model, save_path, plot_name= "T02_2D_hald_domain_periodic" * string(periodic) * "_U" * string(U10) * "_V" * string(V10), N=72*3) 183 | end 184 | -------------------------------------------------------------------------------- /tests/T04_2D_reg_test_netCDF.jl: -------------------------------------------------------------------------------- 1 | 2 | 3 | #using Plots 4 | import Plots as plt 5 | using Setfield, IfElse 6 | 7 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 8 | 9 | import PiCLES: FetchRelations, ParticleTools 10 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 11 | using PiCLES.Operators: TimeSteppers 12 | using PiCLES.Simulations 13 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 14 | 15 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 16 | using PiCLES.Models.WaveGrowthModels2D 17 | 18 | using Oceananigans.TimeSteppers: Clock, tick! 19 | import Oceananigans: fields 20 | using Oceananigans.Units 21 | import Oceananigans.Utils: prettytime 22 | 23 | using PiCLES.Architectures 24 | using GLMakie 25 | 26 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 27 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 28 | 29 | using NCDatasets 30 | using Interpolations 31 | using Dates: Dates as Dates 32 | 33 | using Revise 34 | 35 | # %% 36 | 37 | save_path = "plots/tests/T04_2D_regtest_netCDF/" 38 | mkpath(save_path) 39 | 40 | save_path_data = "data/work/T04_2D_regtest_netCDF/" 41 | mkpath(save_path_data) 42 | 43 | 44 | load_path = "data/work/wind_data/" 45 | 46 | ##### basic parameters 47 | # timestep 48 | DT = 20minutes 49 | # Characterstic wind velocities and std 50 | U10, V10 = 10.0, 10.0 51 | 52 | # Define basic ODE parameters 53 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 54 | 55 | 56 | function interpolate_winds(ds, multiplyer=0) 57 | 58 | Nxx = Int(ceil(ds.attrib["Nx"] * sqrt(2)^multiplyer)) 59 | Nyy = Int(ceil(ds.attrib["Ny"] * sqrt(2)^multiplyer)) 60 | 61 | # define grid based on 62 | grid = TwoDGrid(ds["x"][end], Nxx, ds["y"][end], Nyy) 63 | grid_mesh = TwoDGridMesh(grid, skip=1) 64 | gn = TwoDGridNotes(grid) 65 | 66 | # define time 67 | time_rel = (ds["time"][:] - ds["time"][1]) ./ convert(Dates.Millisecond, Dates.Second(1)) 68 | T = 1day#hours#time_rel[end] 69 | 70 | nodes = (ds["x"][:], ds["y"][:], time_rel) 71 | u_grid = LinearInterpolation(nodes, permutedims(ds["u10m"], [1, 2, 3]), extrapolation_bc=Flat()) 72 | v_grid = LinearInterpolation(nodes, permutedims(ds["v10m"], [1, 2, 3]), extrapolation_bc=Flat()) 73 | 74 | return grid, grid_mesh, gn, T, u_grid, v_grid 75 | end 76 | 77 | # define ODE system and parameters 78 | #particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q); 79 | 80 | 81 | default_ODE_parameters = (r_g=r_g0, C_α=Const_Scg.C_alpha, 82 | C_φ=Const_ID.c_β, C_e=Const_ID.C_e, g=9.81) 83 | 84 | 85 | Revise.retry() 86 | # Default initial conditions based on timestep and chaeracteristic wind velocity 87 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT) 88 | default_particle = ParticleDefaults(WindSeamin["lne"], WindSeamin["cg_bar_x"], WindSeamin["cg_bar_y"], 0.0, 0.0) 89 | 90 | function make_reg_test_store(wave_model, save_path_name) 91 | 92 | ### build Simulation 93 | wave_simulation = Simulation(wave_model, Δt=DT, stop_time=wave_model.ODEsettings.total_time)#1hours) 94 | initialize_simulation!(wave_simulation) 95 | 96 | # run simulation & save simulation 97 | init_state_store!(wave_simulation, save_path_name) 98 | #run!(wave_simulation, cash_store=true, debug=true) 99 | run!(wave_simulation, store=true, cash_store=false, debug=false) 100 | close_store!(wave_simulation) 101 | 102 | end 103 | 104 | # or, alternatively, make movie 105 | function make_reg_test_movie(wave_model, save_path_name; N=36) 106 | 107 | wave_simulation = Simulation(wave_model, Δt=DT, stop_time=wave_model.ODEsettings.total_time)#1hours) 108 | initialize_simulation!(wave_simulation) 109 | 110 | fig, n = init_movie_2D_box_plot(wave_simulation, name_string="T01") 111 | #wave_simulation.stop_time += 1hour 112 | #N = 36 113 | #plot_name = "dummy" 114 | record(fig, save_path_name * ".gif", 1:N, framerate=10) do i 115 | @info "Plotting frame $i of $N..." 116 | @info wave_simulation.model.clock 117 | movie_time_step!(wave_simulation.model, wave_simulation.Δt) 118 | 119 | n[] = 1 120 | end 121 | 122 | end 123 | 124 | 125 | # %% 126 | case = "Test01_2D" 127 | ncfile = load_path * case * ".nc" 128 | ds = Dataset(ncfile, "r") 129 | 130 | # %% 131 | # loop over U10 and V10 range 132 | #case_list = ["Test01_2D"]#, "Test03_2D"]#, "Test04_2D"] 133 | #case_list = ["Test01_2D", "Test02_2D"]#, "Test03_2D", "Test04_2D", "Test05_2D", "Test06_2D", "Test07_2D"] 134 | case_list = ["Test04_2D", "Test05_2D", "Test06_2D", "Test07_2D"] 135 | #for I in CartesianIndices(gridmesh) 136 | for case in case_list 137 | # load netCDF file 138 | #ncfile = "data/work/wind_data/" * case * ".nc" 139 | ncfile = load_path * case * ".nc" 140 | ds = Dataset(ncfile, "r") 141 | 142 | grid, grid_mesh, gn, T, u_grid, v_grid = interpolate_winds(ds) 143 | 144 | u(x, y, t) = u_grid(x, y, t) 145 | v(x, y, t) = v_grid(x, y, t) 146 | winds = (u=u, v=v) 147 | 148 | #winds, u, v =convert_wind_field_functions(u_func, v_func, x, y, t) 149 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q) 150 | 151 | # ... and ODESettings 152 | ODE_settings = PW.ODESettings( 153 | Parameters=default_ODE_parameters, 154 | # define mininum energy threshold 155 | log_energy_minimum=WindSeamin["lne"], 156 | #maximum energy threshold 157 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 158 | saving_step=DT, 159 | timestep=DT, 160 | total_time=T, 161 | adaptive=true, 162 | dt=1e-3, #60*10, 163 | dtmin=1e-4, #60*5, 164 | force_dtmin=true, 165 | callbacks=nothing, 166 | save_everystep=false) 167 | 168 | ## Define wave model 169 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 170 | winds=winds, 171 | ODEsys=particle_system, 172 | ODEsets=ODE_settings, # ODE_settings 173 | ODEinit_type="wind_sea", # default_ODE_parameters 174 | periodic_boundary=false, 175 | boundary_type="same", 176 | minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), # 177 | #minimal_state=FetchRelations.MinimalState(2, 2, DT) * 1, 178 | movie=true) 179 | 180 | 181 | NN =Int(floor(wave_model.ODEsettings.total_time / wave_model.ODEsettings.timestep)) 182 | 183 | # for saving data 184 | # when saving data 185 | save_path_select = save_path_data 186 | mkpath(save_path_select * case) 187 | 188 | #when plotting data 189 | #save_path_select = save_path 190 | #make_reg_test_store(wave_model, save_path_select * case) 191 | 192 | make_reg_test_movie(wave_model, save_path * case, N=NN) 193 | end 194 | -------------------------------------------------------------------------------- /tests/T04_2d_box_diagonal_half_domain.jl: -------------------------------------------------------------------------------- 1 | #ENV["JULIA_INCREMENTAL_COMPILE"] = true 2 | 3 | using Pkg 4 | Pkg.activate("PiCLES/") 5 | 6 | using Pkg 7 | Pkg.activate(".") 8 | 9 | #using Plots 10 | import Plots as plt 11 | using Setfield, IfElse 12 | 13 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 14 | 15 | import PiCLES: FetchRelations, ParticleTools 16 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 17 | using PiCLES.Operators: TimeSteppers 18 | using PiCLES.Simulations 19 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 20 | 21 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 22 | using PiCLES.Models.WaveGrowthModels2D 23 | 24 | using Oceananigans.TimeSteppers: Clock, tick! 25 | import Oceananigans: fields 26 | using Oceananigans.Units 27 | import Oceananigans.Utils: prettytime 28 | 29 | using PiCLES.Architectures 30 | using GLMakie 31 | 32 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 33 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 34 | 35 | using Revise 36 | 37 | # debugging: 38 | #using ProfileView 39 | 40 | # %% 41 | save_path = "plots/tests/T04_box_2_BC/" 42 | mkpath(save_path) 43 | 44 | # % Parameters 45 | U10, V10 = 10.0, 10.0 46 | dt_ODE_save = 30minutes 47 | DT = 30minutes 48 | # version 3 49 | r_g0 = 0.85 50 | 51 | # function to define constants 52 | 53 | 54 | # Const_Scg = PW.get_Scg_constants(C_alpha=-1.41, C_varphi=1.81e-5) 55 | 56 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 57 | 58 | # u_func(x, y, t) = U10 #* sin(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) 59 | # v_func(x, y, t) = V10 #* cos(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) 60 | # u_std = 2e3 * 1 61 | # v_std = 2e3 * 1 62 | # 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π)) 63 | # 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π)) 64 | 65 | # u_func(x, y, t) = 0.1 + IfElse.ifelse.( sin(t * 6 / (1 * 60 * 60 * 2π)) > 0 , 66 | # sin(t * 6 / (1 * 60 * 60 * 2π)) *U10 * exp(-(x - 5e3)^2 / u_std^2) * exp(-(y - 5e3)^2 / v_std^2), 67 | # 0.1) 68 | # v_func(x, y, t) = 0.1 + IfElse.ifelse.(sin(t * 3 / (1 * 60 * 60 * 2π)) > 0, 69 | # 0.0, 70 | # -0.0) 71 | 72 | u_func(x, y, t) = IfElse.ifelse.(x .< y, U10, 0.2) + y * 0 + t * 0 73 | v_func(x, y, t) = IfElse.ifelse.(x .< y, V10, 0.2) + y * 0 + t * 0 74 | 75 | # this shuold hopefully work 76 | # u(x, y, t) = x * 0 + y * 0 + t * 0/ DT + 5.0 77 | # v(x, y, t) = x * 0 + y * 0 + t * 0/ DT + 10.0 78 | 79 | u(x, y, t) = u_func(x, y, t) 80 | v(x, y, t) = v_func(x, y, t) 81 | winds = (u=u, v=v) 82 | 83 | 84 | grid = TwoDGrid(100e3, 51, 100e3, 51) 85 | mesh = TwoDGridMesh(grid, skip=1); 86 | gn = TwoDGridNotes(grid); 87 | 88 | # heatmap( v.(mesh.x, mesh.y, 0) ) 89 | 90 | Revise.retry() 91 | 92 | # define variables based on particle equation 93 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q, input=true, dissipation=true); 94 | 95 | # define V4 parameters absed on Const NamedTuple: 96 | default_ODE_parameters = (r_g=r_g0, C_α=Const_Scg.C_alpha, 97 | C_φ=Const_ID.c_β, C_e=Const_ID.C_e, g=9.81); 98 | 99 | # define setting and standard initial conditions 100 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT); 101 | #WindSeamin = FetchRelations.MinimalWindsea(u(0, 0, 0), v(0, 0, 0), DT / 2) 102 | #WindSeamin = FetchRelations.get_initial_windsea(u(0, 0, 0), v(0, 0, 0), DT/5) 103 | lne_local = log(WindSeamin["E"]) 104 | cg_u_local = WindSeamin["cg_bar_x"] 105 | cg_v_local = WindSeamin["cg_bar_y"] 106 | 107 | ODE_settings = PW.ODESettings( 108 | Parameters=default_ODE_parameters, 109 | # define mininum energy threshold 110 | log_energy_minimum=lne_local,#log(FetchRelations.Eⱼ(0.1, DT)), 111 | #maximum energy threshold 112 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 113 | saving_step=dt_ODE_save, 114 | timestep=DT, 115 | total_time=T = 6days, 116 | adaptive=true, 117 | dt=1e-3, #60*10, 118 | dtmin=1e-4, #60*5, 119 | force_dtmin=true, 120 | callbacks=nothing, 121 | save_everystep=false) 122 | 123 | 124 | default_particle = ParticleDefaults(lne_local, cg_u_local, cg_v_local, 0.0, 0.0) 125 | 126 | 127 | # plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(u.(mesh.x, mesh.y, 0))) 128 | 129 | # plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(v.(mesh.x, mesh.y, 0))) 130 | # %% build model 131 | Revise.retry() 132 | 133 | 134 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 135 | winds=winds, 136 | ODEsys=particle_system, 137 | ODEsets=ODE_settings, # ODE_settings 138 | ODEinit_type="wind_sea", # default_ODE_parameters 139 | periodic_boundary=false, 140 | boundary_type="same", 141 | #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), 142 | movie=true) 143 | 144 | 145 | ### build Simulation 146 | #wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=4hours)#1hours) 147 | wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=6hour)#1hours) 148 | initialize_simulation!(wave_simulation) 149 | 150 | 151 | #init_state_store!(wave_simulation, save_path) 152 | #wave_simulation.model.MovieState = wave_simulation.model.State 153 | 154 | @time run!(wave_simulation, cash_store=true, debug=true) 155 | #reset_simulation!(wave_simulation) 156 | # run simulation 157 | #ProfileView.@profview run!(wave_simulation, cash_store=true, debug=true) 158 | 159 | 160 | istate = wave_simulation.store.store[end]; 161 | p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(istate[:, :, 3])) 162 | 163 | -------------------------------------------------------------------------------- /tests/T06_layers.jl: -------------------------------------------------------------------------------- 1 | #ENV["JULIA_INCREMENTAL_COMPILE"] = true 2 | 3 | using Pkg 4 | #Pkg.activate("../PiCLES/") 5 | 6 | # using Pkg 7 | Pkg.activate(".") 8 | 9 | import Plots as plt 10 | using Setfield, IfElse 11 | 12 | using PiCLES.ParticleSystems: particle_waves_v5 as PW 13 | 14 | import PiCLES: FetchRelations, ParticleTools 15 | using PiCLES.Operators.core_2D: ParticleDefaults, InitParticleInstance, GetGroupVelocity 16 | using PiCLES.Operators: TimeSteppers 17 | using PiCLES.Simulations 18 | using PiCLES.Operators.TimeSteppers: time_step!, movie_time_step! 19 | 20 | using PiCLES.ParticleMesh: TwoDGrid, TwoDGridNotes, TwoDGridMesh 21 | using PiCLES.Models.WaveGrowthModels2D 22 | 23 | using Oceananigans.TimeSteppers: Clock, tick! 24 | import Oceananigans: fields 25 | using Oceananigans.Units 26 | import Oceananigans.Utils: prettytime 27 | 28 | using PiCLES.Architectures 29 | using GLMakie 30 | 31 | using PiCLES.Operators.core_2D: GetGroupVelocity, speed 32 | using PiCLES.Plotting.movie: init_movie_2D_box_plot 33 | 34 | using Revise 35 | 36 | Revise.retry() 37 | using PiCLES: ParticleInstance, ParticleInstance2D, ParticleInstance2DLayer 38 | 39 | 40 | 41 | 42 | # debugging: 43 | #using ProfileView 44 | 45 | # %% 46 | save_path = "plots/tests/T06_layers/" 47 | mkpath(save_path) 48 | 49 | # % Parameters 50 | U10, V10 = 10.0, 10.0 51 | dt_ODE_save = 30minutes 52 | DT = 30minutes 53 | # version 3 54 | 55 | ODEpars, Const_ID, Const_Scg = PW.ODEParameters(r_g=0.85) 56 | 57 | 58 | u_func(x, y, t) = U10 #* sin(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) 59 | v_func(x, y, t) = V10 #* cos(t / (6 * 60 * 60 * 2π)) * sin(x / 50e3) * sin(y / 50e3) 60 | 61 | u(x, y, t) = u_func(x, y, t) 62 | v(x, y, t) = v_func(x, y, t) 63 | winds = (u=u, v=v) 64 | 65 | 66 | grid = TwoDGrid(100e3, 51, 100e3, 51) 67 | mesh = TwoDGridMesh(grid, skip=1); 68 | gn = TwoDGridNotes(grid); 69 | 70 | Revise.retry() 71 | 72 | 73 | #ProfileView.@profview 74 | #ProfileView.@profview 75 | particle_system = PW.particle_equations(u, v, γ=Const_ID.γ, q=Const_ID.q, input=true, dissipation=true); 76 | 77 | # define setting and standard initial conditions 78 | WindSeamin = FetchRelations.MinimalWindsea(U10, V10, DT); 79 | #WindSeamin = FetchRelations.MinimalWindsea(u(0, 0, 0), v(0, 0, 0), DT / 2) 80 | #WindSeamin = FetchRelations.get_initial_windsea(u(0, 0, 0), v(0, 0, 0), DT/5) 81 | lne_local = log(WindSeamin["E"]) 82 | cg_u_local = WindSeamin["cg_bar_x"] 83 | cg_v_local = WindSeamin["cg_bar_y"] 84 | 85 | ODE_settings = PW.ODESettings( 86 | Parameters=ODEpars, 87 | # define mininum energy threshold 88 | log_energy_minimum=lne_local,#log(FetchRelations.Eⱼ(0.1, DT)), 89 | #maximum energy threshold 90 | log_energy_maximum=log(27),#log(17), # correcsponds to Hs about 16 m 91 | saving_step=dt_ODE_save, 92 | timestep=DT, 93 | total_time=T = 6days, 94 | adaptive=true, 95 | dt=1e-3, #60*10, 96 | dtmin=1e-4, #60*5, 97 | force_dtmin=true, 98 | callbacks=nothing, 99 | save_everystep=false) 100 | 101 | 102 | # plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(u.(mesh.x, mesh.y, 0))) 103 | # plt.heatmap(gn.x / 1e3, gn.y / 1e3, transpose(v.(mesh.x, mesh.y, 0))) 104 | # %% build model 105 | 106 | 107 | Revise.retry() 108 | 109 | wave_model = WaveGrowthModels2D.WaveGrowth2D(; grid=grid, 110 | winds=winds, 111 | ODEsys=particle_system, 112 | layers=10, 113 | ODEsets=ODE_settings, # ODE_settings 114 | ODEinit_type="wind_sea", # default_ODE_parameters 115 | periodic_boundary=false, 116 | boundary_type="same", 117 | #minimal_particle=FetchRelations.MinimalParticle(U10, V10, DT), 118 | movie=true) 119 | 120 | 121 | size(wave_model.State) 122 | typeof(wave_model.State) 123 | 124 | 125 | 126 | #particle_system 127 | defaults = ParticleDefaults(0.1, 0.1, 0.1, 0.1, 0.1) 128 | 129 | P1 =InitParticleInstance(particle_system, defaults, ODE_settings, (1, 2), true, true) 130 | 131 | 132 | # 1D 133 | ParticleInstance(1, 2.1, P1.ODEIntegrator, true, true) 134 | # 3d 135 | ParticleInstance2D((1, 2), (2.1, 3.1), P1.ODEIntegrator, true, true) 136 | ParticleInstance((1, 2), (2.1, 3.1), P1.ODEIntegrator, true, true) 137 | # 2d 138 | ParticleInstance2DLayer((1, 2, 1), (2.1, 3.1), P1.ODEIntegrator, true, true) 139 | ParticleInstance((1, 2, 3), (2.1, 3.1), P1.ODEIntegrator, true, true) 140 | 141 | 142 | ### build Simulation 143 | #wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=4hours)#1hours) 144 | 145 | 146 | wave_simulation = Simulation(wave_model, Δt=10minutes, stop_time=6hour)#1hours) 147 | initialize_simulation!(wave_simulation) 148 | 149 | 150 | #init_state_store!(wave_simulation, save_path) 151 | #wave_simulation.model.MovieState = wave_simulation.model.State 152 | 153 | @time run!(wave_simulation, cash_store=true, debug=true) 154 | #reset_simulation!(wave_simulation) 155 | # run simulation 156 | #ProfileView.@profview run!(wave_simulation, cash_store=true, debug=true) 157 | 158 | 159 | istate = wave_simulation.store.store[end]; 160 | p1 = plt.heatmap(gn.x / 1e3, gn.y / 1e3, istate[:, :, 1]) 161 | 162 | -------------------------------------------------------------------------------- /tests/runtests.jl: -------------------------------------------------------------------------------- 1 | using PiCLES 2 | using Test 3 | 4 | @testset "PiCLES.jl" begin 5 | # Write your tests here. 6 | end 7 | -------------------------------------------------------------------------------- /tests/xProject.toml: -------------------------------------------------------------------------------- 1 | name = "PiCLES" 2 | uuid = "79df3bd2-fdbb-4cb7-a58f-f9c8092d6d68" 3 | authors = ["Momme C. Hell"] 4 | version = "0.1.0-DEV" 5 | 6 | [compat] 7 | julia = "1.9.3" 8 | 9 | [deps] 10 | AbstractPlotting = "537997a7-5e4e-5d89-9595-2241ea00577e" 11 | ArgParse = "c7e460c6-2fb9-53a9-8c5b-16f535851c63" 12 | Atom = "c52e3926-4ff0-5f6e-af25-54175e0327b1" 13 | BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" 14 | CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" 15 | Callbacks = "db1e321a-d383-57b4-a664-0144fd54e973" 16 | DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 17 | DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" 18 | DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" 19 | DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" 20 | ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" 21 | GEMPIC = "b6d65c3a-4a4e-11e9-25d0-d309dc85ddeb" 22 | GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" 23 | HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f" 24 | IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" 25 | Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" 26 | JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" 27 | Juno = "e5e0dc1b-0480-54bc-9374-aad01c23163d" 28 | LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" 29 | LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 30 | Meshes = "eacbb407-ea5a-433e-ab97-5258b1ca43fa" 31 | ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" 32 | NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" 33 | NamedTuples = "73a701b4-84e1-5df0-88ff-1968ee2ee8dc" 34 | Oceananigans = "9e8cae18-63c1-5223-a75c-80ca9d6e9a09" 35 | OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" 36 | Pandas = "eadc2687-ae89-51f9-a5d9-86b5a6373a9c" 37 | Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" 38 | PkgTemplates = "14b8a8f1-9102-5b29-a752-f990bacb7fe1" 39 | Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" 40 | Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" 41 | ProfileView = "c46f51b8-102a-5cf2-8d2c-8597cb0e0da7" 42 | PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" 43 | PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" 44 | Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" 45 | Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" 46 | SharedArrays = "1a1011a3-84de-559e-8e89-a11a2f7dc383" 47 | StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" 48 | Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" 49 | UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" 50 | WebIO = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29" 51 | 52 | [extras] 53 | CPUSummary = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" 54 | --------------------------------------------------------------------------------