From ad902882bb9a4365670ee8535abff9ea8de2d8d3 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Thu, 13 Jun 2024 16:07:49 +0200 Subject: [PATCH 1/5] Update Michael's affiliation to U of Augsburg (#545) --- .zenodo.json | 2 +- CODE_OF_CONDUCT.md | 4 ++-- README.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index ecb62381e..1b2cefaeb 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -20,7 +20,7 @@ "orcid": "0000-0001-6083-7038" }, { - "affiliation": "Applied and Computational Mathematics, RWTH Aachen University, Germany", + "affiliation": "High-Performance Scientific Computing, University of Augsburg, Germany", "name": "Schlottke-Lakemper, Michael", "orcid": "0000-0002-3195-2536" }, diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 5c74bcf79..e9f99ce1b 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -60,7 +60,7 @@ representative at an online or offline event. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to -[Michael Schlottke-Lakemper](mailto:m.schlottke-lakemper@acom.rwth-aachen.de), +[Michael Schlottke-Lakemper](mailto:michael.schlottke-lakemper@uni-a.de), [Sven Berger](mailto:sven.berger@hereon.de), or any other of the principal developers responsible for enforcement listed in [AUTHORS.md](AUTHORS.md). @@ -128,4 +128,4 @@ enforcement ladder](https://github.com/mozilla/diversity). For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. \ No newline at end of file +https://www.contributor-covenant.org/translations. diff --git a/README.md b/README.md index 9f5defe1a..b40e68fbc 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ with the help of TrixiParticles.jl, please cite it as ## Authors Erik Faulhaber (University of Cologne) and Niklas Neher (HLRS) implemented the foundations for TrixiParticles.jl and are principal developers along with Sven Berger (hereon). -The project was started by Michael Schlottke-Lakemper (RWTH Aachen University/HLRS) +The project was started by Michael Schlottke-Lakemper (University of Augsburg) and Gregor Gassner (University of Cologne), who provide scientific direction and technical advice. The full list of contributors can be found in [AUTHORS.md](AUTHORS.md). From c5dfd077efa620685032788467cf9c759b6fd2a8 Mon Sep 17 00:00:00 2001 From: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Date: Mon, 17 Jun 2024 09:43:23 +0200 Subject: [PATCH 2/5] Precompute git hash to avoid overhead (#542) * Precompute git hash * Store git hash in callbacks * Fix --------- Co-authored-by: Niklas Neher <73897120+LasNikas@users.noreply.github.com> --- src/callbacks/post_process.jl | 15 ++++++++++----- src/callbacks/solution_saving.jl | 16 ++++++++-------- src/general/file_system.jl | 31 ------------------------------- src/general/general.jl | 4 +++- src/util.jl | 18 ++++++++++++++++++ src/visualization/write2vtk.jl | 27 ++++++++++++++++++--------- 6 files changed, 57 insertions(+), 54 deletions(-) delete mode 100644 src/general/file_system.jl diff --git a/src/callbacks/post_process.jl b/src/callbacks/post_process.jl index e2e98a2a0..d68168258 100644 --- a/src/callbacks/post_process.jl +++ b/src/callbacks/post_process.jl @@ -73,6 +73,7 @@ struct PostprocessCallback{I, F} append_timestamp :: Bool write_csv :: Bool write_json :: Bool + git_hash :: Ref{String} end function PostprocessCallback(; interval::Integer=0, dt=0.0, exclude_boundary=true, @@ -94,7 +95,8 @@ function PostprocessCallback(; interval::Integer=0, dt=0.0, exclude_boundary=tru post_callback = PostprocessCallback(interval, write_file_interval, Dict{String, Vector{Any}}(), Float64[], exclude_boundary, funcs, filename, output_directory, - append_timestamp, write_csv, write_json) + append_timestamp, write_csv, write_json, + Ref("UnknownVersion")) if dt > 0 # Add a `tstop` every `dt`, and save the final solution return PeriodicCallback(post_callback, dt, @@ -209,9 +211,12 @@ function initialize_postprocess_callback!(cb, u, t, integrator) end function initialize_postprocess_callback!(cb::PostprocessCallback, u, t, integrator) + cb.git_hash[] = compute_git_hash() + # Apply the callback cb(integrator) - return nothing + + return cb end # `condition` with interval @@ -281,7 +286,7 @@ function write_postprocess_callback(pp::PostprocessCallback) mkpath(pp.output_directory) data = Dict{String, Any}() - write_meta_data!(data) + write_meta_data!(data, pp.git_hash[]) prepare_series_data!(data, pp) time_stamp = "" @@ -331,9 +336,9 @@ function create_series_dict(values, times, system_name="") "time" => times) end -function write_meta_data!(data) +function write_meta_data!(data, git_hash) meta_data = Dict("solver_name" => "TrixiParticles.jl", - "solver_version" => get_git_hash(), + "solver_version" => git_hash, "julia_version" => string(VERSION)) data["meta"] = meta_data diff --git a/src/callbacks/solution_saving.jl b/src/callbacks/solution_saving.jl index 5163199d6..04552d57e 100644 --- a/src/callbacks/solution_saving.jl +++ b/src/callbacks/solution_saving.jl @@ -77,6 +77,7 @@ mutable struct SolutionSavingCallback{I, CQ} max_coordinates :: Float64 custom_quantities :: CQ latest_saved_iter :: Int + git_hash :: Ref{String} end function SolutionSavingCallback(; interval::Integer=0, dt=0.0, @@ -102,7 +103,7 @@ function SolutionSavingCallback(; interval::Integer=0, dt=0.0, save_initial_solution, save_final_solution, write_meta_data, verbose, output_directory, prefix, max_coordinates, custom_quantities, - -1) + -1, Ref("UnknownVersion")) if length(save_times) > 0 # See the large comment below for an explanation why we use `finalize` here @@ -131,6 +132,7 @@ end function initialize_save_cb!(solution_callback::SolutionSavingCallback, u, t, integrator) # Reset `latest_saved_iter` solution_callback.latest_saved_iter = -1 + solution_callback.git_hash[] = compute_git_hash() # Save initial solution if solution_callback.save_initial_solution @@ -156,7 +158,7 @@ end # `affect!` function (solution_callback::SolutionSavingCallback)(integrator) - (; interval, output_directory, custom_quantities, write_meta_data, + (; interval, output_directory, custom_quantities, write_meta_data, git_hash, verbose, prefix, latest_saved_iter, max_coordinates) = solution_callback vu_ode = integrator.u @@ -178,12 +180,10 @@ function (solution_callback::SolutionSavingCallback)(integrator) println("Writing solution to $output_directory at t = $(integrator.t)") end - @trixi_timeit timer() "save solution" trixi2vtk(vu_ode, semi, integrator.t; iter=iter, - output_directory=output_directory, - prefix=prefix, - write_meta_data=write_meta_data, - max_coordinates=max_coordinates, - custom_quantities...) + @trixi_timeit timer() "save solution" trixi2vtk(vu_ode, semi, integrator.t; + iter, output_directory, prefix, + write_meta_data, git_hash=git_hash[], + max_coordinates, custom_quantities...) # Tell OrdinaryDiffEq that `u` has not been modified u_modified!(integrator, false) diff --git a/src/general/file_system.jl b/src/general/file_system.jl deleted file mode 100644 index 0cc4cc56d..000000000 --- a/src/general/file_system.jl +++ /dev/null @@ -1,31 +0,0 @@ -vtkname(system::FluidSystem) = "fluid" -vtkname(system::SolidSystem) = "solid" -vtkname(system::BoundarySystem) = "boundary" - -function system_names(systems) - # Add `_i` to each system name, where `i` is the index of the corresponding - # system type. - # `["fluid", "boundary", "boundary"]` becomes `["fluid_1", "boundary_1", "boundary_2"]`. - cnames = systems .|> vtkname - filenames = [string(cnames[i], "_", count(==(cnames[i]), cnames[1:i])) - for i in eachindex(cnames)] - return filenames -end - -function get_git_hash() - pkg_directory = pkgdir(@__MODULE__) - git_directory = joinpath(pkg_directory, ".git") - - # Check if the .git directory exists - if !isdir(git_directory) - return "UnknownVersion" - end - - try - git_cmd = Cmd(`git describe --tags --always --first-parent --dirty`, - dir=pkg_directory) - return string(readchomp(git_cmd)) - catch e - return "UnknownVersion" - end -end diff --git a/src/general/general.jl b/src/general/general.jl index dfe52e06a..4a60cb52f 100644 --- a/src/general/general.jl +++ b/src/general/general.jl @@ -7,12 +7,15 @@ GPUSystem = System{NDIMS, Nothing} where {NDIMS} abstract type FluidSystem{NDIMS, IC} <: System{NDIMS, IC} end timer_name(::FluidSystem) = "fluid" +vtkname(system::FluidSystem) = "fluid" abstract type SolidSystem{NDIMS, IC} <: System{NDIMS, IC} end timer_name(::SolidSystem) = "solid" +vtkname(system::SolidSystem) = "solid" abstract type BoundarySystem{NDIMS, IC} <: System{NDIMS, IC} end timer_name(::BoundarySystem) = "boundary" +vtkname(system::BoundarySystem) = "boundary" @inline function set_zero!(du) du .= zero(eltype(du)) @@ -29,6 +32,5 @@ include("smoothing_kernels.jl") include("initial_condition.jl") include("system.jl") include("interpolation.jl") -include("file_system.jl") include("custom_quantities.jl") include("neighborhood_search.jl") diff --git a/src/util.jl b/src/util.jl index 2dc86a267..b3cbfb764 100644 --- a/src/util.jl +++ b/src/util.jl @@ -206,3 +206,21 @@ end function type2string(type) return string(nameof(typeof(type))) end + +function compute_git_hash() + pkg_directory = pkgdir(@__MODULE__) + git_directory = joinpath(pkg_directory, ".git") + + # Check if the .git directory exists + if !isdir(git_directory) + return "UnknownVersion" + end + + try + git_cmd = Cmd(`git describe --tags --always --first-parent --dirty`, + dir=pkg_directory) + return string(readchomp(git_cmd)) + catch e + return "UnknownVersion" + end +end diff --git a/src/visualization/write2vtk.jl b/src/visualization/write2vtk.jl index bd1658e32..a05e6727e 100644 --- a/src/visualization/write2vtk.jl +++ b/src/visualization/write2vtk.jl @@ -1,3 +1,13 @@ +function system_names(systems) + # Add `_i` to each system name, where `i` is the index of the corresponding + # system type. + # `["fluid", "boundary", "boundary"]` becomes `["fluid_1", "boundary_1", "boundary_2"]`. + cnames = vtkname.(systems) + filenames = [string(cnames[i], "_", count(==(cnames[i]), cnames[1:i])) + for i in eachindex(cnames)] + return filenames +end + """ trixi2vtk(vu_ode, semi, t; iter=nothing, output_directory="out", prefix="", write_meta_data=true, max_coordinates=Inf, custom_quantities...) @@ -39,13 +49,14 @@ trixi2vtk(sol.u[end], semi, 0.0, iter=1, my_custom_quantity=kinetic_energy) ``` """ function trixi2vtk(vu_ode, semi, t; iter=nothing, output_directory="out", prefix="", - write_meta_data=true, max_coordinates=Inf, custom_quantities...) + write_meta_data=true, git_hash=compute_git_hash(), + max_coordinates=Inf, custom_quantities...) (; systems) = semi v_ode, u_ode = vu_ode.x # Update quantities that are stored in the systems. These quantities (e.g. pressure) # still have the values from the last stage of the previous step if not updated here. - update_systems_and_nhs(v_ode, u_ode, semi, t) + @trixi_timeit timer() "update systems" update_systems_and_nhs(v_ode, u_ode, semi, t) filenames = system_names(systems) @@ -57,17 +68,15 @@ function trixi2vtk(vu_ode, semi, t; iter=nothing, output_directory="out", prefix periodic_box = get_neighborhood_search(system, semi).periodic_box trixi2vtk(v, u, t, system, periodic_box; - output_directory=output_directory, - system_name=filenames[system_index], iter=iter, prefix=prefix, - write_meta_data=write_meta_data, max_coordinates=max_coordinates, - custom_quantities...) + system_name=filenames[system_index], output_directory, iter, prefix, + write_meta_data, git_hash, max_coordinates, custom_quantities...) end end # Convert data for a single TrixiParticle system to VTK format function trixi2vtk(v, u, t, system, periodic_box; output_directory="out", prefix="", iter=nothing, system_name=vtkname(system), write_meta_data=true, - max_coordinates=Inf, + max_coordinates=Inf, git_hash=compute_git_hash(), custom_quantities...) mkpath(output_directory) @@ -98,7 +107,7 @@ function trixi2vtk(v, u, t, system, periodic_box; output_directory="out", prefix end end - vtk_grid(file, points, cells) do vtk + @trixi_timeit timer() "write to vtk" vtk_grid(file, points, cells) do vtk # dispatches based on the different system types e.g. FluidSystem, TotalLagrangianSPHSystem write2vtk!(vtk, v, u, t, system, write_meta_data=write_meta_data) @@ -107,7 +116,7 @@ function trixi2vtk(v, u, t, system, periodic_box; output_directory="out", prefix vtk["time"] = t if write_meta_data - vtk["solver_version"] = get_git_hash() + vtk["solver_version"] = git_hash vtk["julia_version"] = string(VERSION) end From 5deebdd94bd01e785d3e67d742689f5bd606d061 Mon Sep 17 00:00:00 2001 From: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:17:01 +0200 Subject: [PATCH 3/5] Move timers and `@trixi_timeit` to TrixiBase.jl (#543) * Move timers and `@trixi_timeit` to TrixiBase.jl * Require latest version of TrixiBase.jl * Fix tests --------- Co-authored-by: Niklas Neher <73897120+LasNikas@users.noreply.github.com> --- Project.toml | 2 +- examples/n_body/n_body_benchmark_trixi.jl | 4 +-- examples/n_body/n_body_solar_system.jl | 4 +-- src/TrixiParticles.jl | 3 +- src/util.jl | 42 ----------------------- test/count_allocations.jl | 4 +-- 6 files changed, 9 insertions(+), 50 deletions(-) diff --git a/Project.toml b/Project.toml index ea1bc9aa5..bff9874c1 100644 --- a/Project.toml +++ b/Project.toml @@ -42,7 +42,7 @@ SciMLBase = "1, 2" StaticArrays = "1" StrideArrays = "0.1" TimerOutputs = "0.5" -TrixiBase = "0.1" +TrixiBase = "0.1.3" PointNeighbors = "0.2" WriteVTK = "1" julia = "1.9" diff --git a/examples/n_body/n_body_benchmark_trixi.jl b/examples/n_body/n_body_benchmark_trixi.jl index 04c1f1af6..b47f689e7 100644 --- a/examples/n_body/n_body_benchmark_trixi.jl +++ b/examples/n_body/n_body_benchmark_trixi.jl @@ -108,7 +108,7 @@ end filename = tempname() open(filename, "w") do f redirect_stderr(f) do - TrixiParticles.TimerOutputs.disable_debug_timings(TrixiParticles) + TrixiParticles.disable_debug_timings() end end @@ -124,6 +124,6 @@ end # Enable timers again open(filename, "w") do f redirect_stderr(f) do - TrixiParticles.TimerOutputs.enable_debug_timings(TrixiParticles) + TrixiParticles.enable_debug_timings() end end diff --git a/examples/n_body/n_body_solar_system.jl b/examples/n_body/n_body_solar_system.jl index 6fa860089..b4da85aeb 100644 --- a/examples/n_body/n_body_solar_system.jl +++ b/examples/n_body/n_body_solar_system.jl @@ -49,7 +49,7 @@ callbacks = CallbackSet(info_callback, saving_callback) filename = tempname() open(filename, "w") do f redirect_stderr(f) do - TrixiParticles.TimerOutputs.disable_debug_timings(TrixiParticles) + TrixiParticles.disable_debug_timings() end end @@ -63,6 +63,6 @@ sol = solve(ode, SymplecticEuler(), # Enable timers again open(filename, "w") do f redirect_stderr(f) do - TrixiParticles.TimerOutputs.enable_debug_timings(TrixiParticles) + TrixiParticles.enable_debug_timings() end end diff --git a/src/TrixiParticles.jl b/src/TrixiParticles.jl index f170e08d8..2fe865d10 100644 --- a/src/TrixiParticles.jl +++ b/src/TrixiParticles.jl @@ -21,7 +21,8 @@ using SciMLBase: CallbackSet, DiscreteCallback, DynamicalODEProblem, u_modified! using StaticArrays: @SMatrix, SMatrix, setindex using StrideArrays: PtrArray, StaticInt using TimerOutputs: TimerOutput, TimerOutputs, print_timer, reset_timer! -using TrixiBase: trixi_include +using TrixiBase: trixi_include, @trixi_timeit, timer, timeit_debug_enabled, + disable_debug_timings, enable_debug_timings @reexport using PointNeighbors: TrivialNeighborhoodSearch, GridNeighborhoodSearch using PointNeighbors: PointNeighbors, for_particle_neighbor using WriteVTK: vtk_grid, MeshCell, VTKCellTypes, paraview_collection, vtk_save diff --git a/src/util.jl b/src/util.jl index b3cbfb764..338a94415 100644 --- a/src/util.jl +++ b/src/util.jl @@ -26,48 +26,6 @@ function print_startup_message() println(s) end -# Enable debug timings `@trixi_timeit timer() "name" stuff...`. -# This allows us to disable timings completely by executing -# `TimerOutputs.disable_debug_timings(TrixiParticles)` -# and to enable them again by executing -# `TimerOutputs.enable_debug_timings(TrixiParticles)` -timeit_debug_enabled() = true - -# Store main timer for global timing of functions -const main_timer = TimerOutput() - -# Always call timer() to hide implementation details -timer() = main_timer - -# @trixi_timeit timer() "some label" expression -# -# Basically the same as a special case of `@timeit_debug` from -# [TimerOutputs.jl](https://github.com/KristofferC/TimerOutputs.jl), -# but without `try ... finally ... end` block. Thus, it's not exception-safe, -# but it also avoids some related performance problems. Since we do not use -# exception handling in TrixiParticles, that's not really an issue. -# -# Copied from [Trixi.jl](https://github.com/trixi-framework/Trixi.jl). -macro trixi_timeit(timer_output, label, expr) - timeit_block = quote - if timeit_debug_enabled() - local to = $(esc(timer_output)) - local enabled = to.enabled - if enabled - local accumulated_data = $(TimerOutputs.push!)(to, $(esc(label))) - end - local b0 = $(TimerOutputs.gc_bytes)() - local t0 = $(TimerOutputs.time_ns)() - end - local val = $(esc(expr)) - if timeit_debug_enabled() && enabled - $(TimerOutputs.do_accumulate!)(accumulated_data, t0, b0) - $(TimerOutputs.pop!)(to) - end - val - end -end - """ @threaded for ... end diff --git a/test/count_allocations.jl b/test/count_allocations.jl index 3b5110ba1..1c597f9a0 100644 --- a/test/count_allocations.jl +++ b/test/count_allocations.jl @@ -45,7 +45,7 @@ function count_rhs_allocations(sol, semi) try # Disable timers, which cause extra allocations - TrixiParticles.TimerOutputs.disable_debug_timings(TrixiParticles) + TrixiParticles.disable_debug_timings() # Disable multithreading, which causes extra allocations return disable_polyester_threads() do @@ -57,7 +57,7 @@ function count_rhs_allocations(sol, semi) end finally # Enable timers again - @invokelatest TrixiParticles.TimerOutputs.enable_debug_timings(TrixiParticles) + @invokelatest TrixiParticles.enable_debug_timings() end end From 4af461da201fa6f817ce11d92437fb0c66beecb2 Mon Sep 17 00:00:00 2001 From: Niklas Neher <73897120+LasNikas@users.noreply.github.com> Date: Wed, 19 Jun 2024 09:43:16 +0200 Subject: [PATCH 4/5] Add `trixi2vtk` wrapper for `InitialCondition` (#546) * add wrapper * modify kwarg * implement suggestions --- src/visualization/write2vtk.jl | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/visualization/write2vtk.jl b/src/visualization/write2vtk.jl index a05e6727e..2a4c9f207 100644 --- a/src/visualization/write2vtk.jl +++ b/src/visualization/write2vtk.jl @@ -183,6 +183,32 @@ function trixi2vtk(coordinates; output_directory="out", prefix="", filename="coo return file end +""" + trixi2vtk(initial_condition::InitialCondition; output_directory="out", + prefix="", filename="initial_condition", custom_quantities...) + +Convert [`InitialCondition`](@ref) data to VTK format. + +# Arguments +- `initial_condition`: [`InitialCondition`](@ref) to be saved. + +# Keywords +- `output_directory="out"`: Output directory path. +- `prefix=""`: Prefix for the output file. +- `filename="coordinates"`: Name of the output file. + +# Returns +- `file::AbstractString`: Path to the generated VTK file. +""" +function trixi2vtk(initial_condition::InitialCondition; output_directory="out", + prefix="", filename="initial_condition", custom_quantities...) + (; coordinates, velocity, density, mass, pressure) = initial_condition + + return trixi2vtk(coordinates; output_directory, prefix, filename, + density=density, initial_velocity=velocity, mass=mass, + pressure=pressure) +end + function write2vtk!(vtk, v, u, t, system; write_meta_data=true) vtk["velocity"] = view(v, 1:ndims(system), :) From 39bc7985b8df42beae8b58984b59a9a251544bfa Mon Sep 17 00:00:00 2001 From: Sven Berger Date: Wed, 19 Jun 2024 10:44:19 +0200 Subject: [PATCH 5/5] Example on how to save interpolated planes using postprocessing callback (#462) * add example * replace MSE with MRE * Revert "replace MSE with MRE" This reverts commit 1e0090794f7c13ea02b5c3ae298514caab93f0a4. * revert * update * format * fix and reduce runtime * Fix comment * implement suggestions * format --------- Co-authored-by: Erik Faulhaber <44124897+efaulhaber@users.noreply.github.com> --- .../postprocessing/interpolation_plane.jl | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/examples/postprocessing/interpolation_plane.jl b/examples/postprocessing/interpolation_plane.jl index 5c94df996..ea273d0fc 100644 --- a/examples/postprocessing/interpolation_plane.jl +++ b/examples/postprocessing/interpolation_plane.jl @@ -96,3 +96,25 @@ plot_3d = Plots.plot(scatter_3d, xlabel="X", ylabel="Y", zlabel="Z", combined_plot = Plots.plot(plot1, plot2, plot3, plot_3d, layout=(2, 2), size=(1000, 1500), margin=3mm) + +# If we want to save planes at regular intervals, we can use the postprocessing callback. +function save_interpolated_plane(v, u, t, system) + # Size of the patch to be interpolated + interpolation_start = [0.0, 0.0] + interpolation_end = [tank_size[1], tank_size[2]] + + # The resolution the plane is interpolated to. In this case twice the original resolution. + resolution = 0.5 * fluid_particle_spacing + + file_id = ceil(Int, t * 10000) + interpolate_plane_2d_vtk(interpolation_start, interpolation_end, resolution, + semi, system, v, u, filename="plane_$file_id.vti") + return nothing +end + +save_interpolation_cb = PostprocessCallback(; dt=0.1, write_file_interval=0, + save_interpolated_plane) + +trixi_include(@__MODULE__, + joinpath(examples_dir(), "fluid", "dam_break_2d.jl"), tspan=(0.0, 0.2), + extra_callback=save_interpolation_cb, fluid_particle_spacing=0.01)