-
Notifications
You must be signed in to change notification settings - Fork 16
how to parameter study #269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
robertweinbrenner
wants to merge
8
commits into
kaipartmann:main
Choose a base branch
from
robertweinbrenner:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+274
−0
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
cd77f67
Erste Version
robertweinbrenner f79dd2b
Erste Version neu
robertweinbrenner eab02ff
Erste Version neu
robertweinbrenner a19186a
Update docs/src/howto_parameter-study.md
robertweinbrenner 0db131f
Update docs/src/howto_parameter-study.md
robertweinbrenner c1234dc
Update regarding the comments
robertweinbrenner 1b4f2ec
Minor hints regarding the do-syntax
kaipartmann e16a2ae
Update of the postprocessing part
robertweinbrenner File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| using Peridynamics | ||
| using Printf | ||
| using DelimitedFiles | ||
|
|
||
| ## PARAMETER STUDY SIMULATIONS | ||
| function job_xwave(setup, root) | ||
| (; E, nu, rho, T, vmax, npyz, m) = setup | ||
| lx, lyz = 0.2, 0.002 | ||
| Δx = lyz / npyz | ||
| pos, vol = uniform_box(lx, lyz, lyz, Δx) | ||
| ids = sortperm(pos[1,:]) | ||
| body = Body(BBMaterial(), pos[:, ids], vol[ids]) | ||
| horizon = m * Δx | ||
| material!(body; horizon, rho, E, nu) | ||
| point_set!(x -> x < -lx / 2 + 1.2Δx, body, :left) | ||
| velocity_bc!(t -> t < T ? vmax * sin(2π / T * t) : 0.0, body, :left, :x) | ||
| vv = VelocityVerlet(time=1e-4, safety_factor=0.7) | ||
| simname = @sprintf("xwave_npyz-%d_m-%d", npyz, round(Int, m)) | ||
| path = joinpath(root, simname) | ||
| job = Job(body, vv; path, freq=5, fields=(:displacement,)) | ||
| return job | ||
| end | ||
| setups = [ | ||
| (; E=210e9, nu=0.25, rho=7850.0, T=1.0e-5, vmax=2.0, npyz=4, m=3.015), | ||
| (; E=210e9, nu=0.25, rho=7850.0, T=1.0e-5, vmax=2.0, npyz=4, m=4.015), | ||
| (; E=210e9, nu=0.25, rho=7850.0, T=1.0e-5, vmax=2.0, npyz=4, m=5.015), | ||
| ] | ||
| root = joinpath("results", "xwave_study") | ||
| rm(root; recursive=true, force=true) | ||
|
|
||
|
|
||
| study = Study(job_xwave, setups; root) | ||
|
|
||
| ## SUBMIT STUDY | ||
| submit!(study) | ||
|
|
||
| ## POST-PROCESSING | ||
| function calc_velocity(t, x_w, u_w) # Berechnung der Wellengeschwindigkeit anhand der Position und Verschiebung der Welle | ||
| u_0 = first(u_w) # Anfangsverschiebung der Welle | ||
| valid_until = findfirst(x -> !isapprox(u_0, x; rtol=0.01), u_w) | ||
| if !isnothing(valid_until) # Überprüfung, ob ein gültiger Punkt gefunden wurde | ||
| x_w = x_w[1:valid_until-1] # Beschränkung der Positions-Daten auf gültige Punkte | ||
| t = t[1:valid_until-1] # Beschränkung der Zeit-Daten auf gültige Punkte | ||
| end | ||
| n = length(t) # Anzahl der Datenpunkte | ||
| @assert n == length(x_w) # Sicherstellen, dass die Längen übereinstimmen | ||
| t̄ = sum(t) / n #Berechnung des Mittelwerts der Zeit | ||
| x̄ = sum(x_w) / n #Berechnung des Mittelwerts der Position | ||
| v = sum((t .- t̄) .* (x_w .- x̄)) / sum((t .- t̄) .^ 2) #Berechnung der Steigung der Regressionsgeraden = Geschwindigkeit | ||
| return v # Rückgabe der berechneten Geschwindigkeit | ||
| end | ||
|
|
||
| default_result = (; c_0=NaN, c_w=NaN, dc=NaN, dcp=NaN) # Standard-Ergebnisstruktur für Post-Processing-Ergebnisse | ||
| results = process_each_job(study, default_result) do job, setup # Post-Processing für jede Simulation im Parameter-Studium | ||
| # extract parameters that are needed for post-processing | ||
| (; E, rho, T, npyz) = setup | ||
| Δx = 0.002 / npyz | ||
|
|
||
| # prepare some output files | ||
| post_path = joinpath(job.options.root, "post") # Pfad für Post-Processing-Daten | ||
| mkpath(post_path) # required to ensure the directory exists (Erstellt das Verzeichnis für die Post-Processing-Daten) | ||
| wave_position_data_file = joinpath(post_path, "wavepos.csv") # Datei zur Speicherung der Wellenpositionsdaten | ||
|
|
||
| # get the wave position over time | ||
| process_each_export(job; serial=true) do r0, r, id # Liest die Position und Verschiebung der Welle aus den Export-Dateien | ||
| t = first(r[:time]) | ||
| t < 1.5T && return nothing # nur Zeitpunkte größer als 1.5T berücksichtigen | ||
| ymax = @views maximum(r0[:position][2, :]) # maximale y-position | ||
| pids = findall(eachcol(r0[:position])) do point | ||
| isapprox(point[2], ymax; atol=1.01Δx/2) | ||
| end | ||
| û, pids_id = @views findmax(r[:displacement][1, pids]) # maximale Verschiebung der Welle in x-Richtung | ||
| x̂ = r[:position][1, pids[pids_id]] # Position der Welle in x-Richtung zum gegebenen Zeitpunkt | ||
| open(wave_position_data_file, "a+") do io # speichert die Zeit, Position und Verschiebung der Welle in CSV-Datei | ||
| @printf(io, "%.12f,%.12f,%.12f\n", t, x̂, û) | ||
| end | ||
| return nothing | ||
| end | ||
|
|
||
| # calculate wave speed | ||
| results = readdlm(wave_position_data_file, ',', Float64) | ||
| t, x̂, û = results[:,1], results[:,2], results[:,3] | ||
| c_0 = sqrt(E / rho) # theoretische Wellengeschwindigkeit | ||
| c_w = calc_velocity(t, x̂, û) # Berechnung der Wellengeschwindigkeit anhand Simulationsdaten | ||
| dc = c_w - c_0 # Differenz der Wellengeschwindigkeiten | ||
| dcp = 100 * dc / c_0 # prozentuale Abweichung der Wellengeschwindigkeiten | ||
| printstyled("\nRESULTS FOR SIMULATION: `$(basename(job.options.root))`:\n", bold=true) | ||
| printstyled(@sprintf("c_0 = %8.2f m/s\n", c_0); color=:green, bold=true) | ||
| printstyled(@sprintf("c_w = %8.2f m/s\n", c_w); color=:blue, bold=true) | ||
| printstyled(@sprintf("Δc = %8.2f m/s (%.3f %%)\n", dc, dcp); color=:red, bold=true) | ||
|
|
||
| return (; c_0, c_w, dc, dcp) | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,180 @@ | ||
| # Perform a parameter study | ||
|
|
||
| The following section explains how to perform a parameter study. | ||
|
|
||
| ### 1. Define the simulation conditions | ||
|
|
||
| Here is an example function that creates a peridynamic body and defines the boundary conditions of each simulation. | ||
| This simulation is intended to simulate wave propagation in the defined body. | ||
|
|
||
| ```julia | ||
| function job_xwave(setup, root) | ||
| (; E, nu, rho, T, vmax, npyz, m) = setup | ||
| lx, lyz = 0.2, 0.002 | ||
| Δx = lyz / npyz | ||
| pos, vol = uniform_box(lx, lyz, lyz, Δx) | ||
| ids = sortperm(pos[1,:]) | ||
| body = Body(BBMaterial(), pos[:, ids], vol[ids]) | ||
| horizon = m * Δx | ||
| material!(body; horizon, rho, E, nu) | ||
| point_set!(x -> x < -lx / 2 + 1.2Δx, body, :left) | ||
| velocity_bc!(t -> t < T ? vmax * sin(2π / T * t) : 0.0, body, :left, :x) | ||
| vv = VelocityVerlet(time=1e-4, safety_factor=0.7) | ||
| simname = @sprintf("xwave_npyz-%d_m-%d", npyz, round(Int, m)) | ||
| path = joinpath(root, simname) | ||
| job = Job(body, vv; path, freq=5, fields=(:displacement,)) | ||
| return job | ||
| end | ||
| ``` | ||
|
|
||
| The line | ||
| ```julia | ||
| (; E, nu, rho, T, vmax, npyz, m) = setup | ||
| ``` | ||
| creates a setup in which the material parameters are defined. | ||
|
|
||
|
|
||
| Now various setups are created in which the respective parameters are defined as desired. A separate simulation is performed for each setup. Here the parameter `m`, which controls the peridynamic horizon `h = m * Δx`, varies. | ||
|
|
||
| ```julia | ||
| setups = [ | ||
| (; E=210e9, nu=0.25, rho=7850.0, T=1.0e-5, vmax=2.0, npyz=4, m=3.015), | ||
| (; E=210e9, nu=0.25, rho=7850.0, T=1.0e-5, vmax=2.0, npyz=4, m=4.015), | ||
| (; E=210e9, nu=0.25, rho=7850.0, T=1.0e-5, vmax=2.0, npyz=4, m=5.015), | ||
| ] | ||
| ``` | ||
|
|
||
| The location where the simulation results are to be stored can be specified with `joinpath` | ||
| ```julia | ||
| root = joinpath("results", "xwave_study") | ||
| ``` | ||
|
|
||
| ### 2. Submit study | ||
|
|
||
| To execute the previously defined setups one after the other, first create a study object and then call `submit!`: | ||
| ```julia | ||
| study = Study(job_xwave, setups; root) | ||
| submit!(study) | ||
| ``` | ||
|
|
||
|
|
||
| ### 3. Postprocessing | ||
|
|
||
| Now that the simulations are complete, the post-processing can begin. This is necessary in order to calculate and display the actual values needed from the raw data generated. In this example the needed values are the theoretical wave velocity `c_0`, the measured wave velocity from the simulation `c_w` and the difference between them two `dc` as well as the percentage deviation `dcp`. | ||
|
|
||
| The complete postprocessing code is shown below and will be discussed in the following sections. | ||
|
|
||
| ```julia | ||
| default_result = (; c_0=NaN, c_w=NaN, dc=NaN, dcp=NaN) | ||
| results = process_each_job(study, default_result) do job, setup | ||
| (; E, rho, T, npyz) = setup | ||
| Δx = 0.002 / npyz | ||
|
|
||
| default_exp_ret = (; time=NaN, wave_position=NaN, amplitude_ux=NaN) | ||
| res = process_each_export(job, default_exp_ret) do r0, r, id | ||
| t = first(r[:time]) | ||
| t < 1.5T && return default_exp_ret | ||
| ymax = @views maximum(r0[:position][2, :]) | ||
| pids = findall(eachcol(r0[:position])) do point | ||
| isapprox(point[2], ymax; atol=1.01Δx/2) | ||
| end | ||
| û, pids_id = @views findmax(r[:displacement][1, pids]) | ||
| x̂ = r[:position][1, pids[pids_id]] | ||
| return (; time=t, wave_position=x̂, amplitude_ux=û) | ||
| end | ||
|
|
||
| allres = (; (k => getfield.(res, k) for k in keys(default_exp_ret))...) | ||
| (; time, wave_position, amplitude_ux) = allres | ||
| idxs = findall(x -> !isnan(x), time) | ||
|
|
||
| c_0 = sqrt(E / rho) | ||
| c_w = calc_velocity(time[idxs], wave_position[idxs], amplitude_ux[idxs]) | ||
| dc = c_w - c_0 | ||
| dcp = 100 * dc / c_0 | ||
|
|
||
| @mpiroot begin | ||
| bold = true | ||
| simname = basename(job.options.root) | ||
| printstyled("\nRESULTS FOR SIMULATION: `$(simname)`:\n"; bold) | ||
| printstyled(@sprintf("c_0 = %8.2f m/s\n", c_0); color=:green, bold) | ||
| printstyled(@sprintf("c_w = %8.2f m/s\n", c_w); color=:blue, bold) | ||
| printstyled(@sprintf("Δc = %8.2f m/s (%.3f %%)\n", dc, dcp); color=:red, bold) | ||
| end | ||
|
|
||
| return (; c_0, c_w, dc, dcp) | ||
| end | ||
| ``` | ||
|
|
||
|
|
||
| #### 3.1 Postprocessing function | ||
|
|
||
| First, `default_result` is used to define a default result structure (a NamedTuple). | ||
| The function `process_each_job` then runs through all simulations (`study`) and executes the postprocessing code listed in sections 3.2-3 for each individual setup. The results are stored in `res`. | ||
| The `do` block receives `job` and `setup` as parameters and returns the calculated results for each simulation. | ||
|
|
||
|
|
||
| ```julia | ||
| default_result = (; c_0=NaN, c_w=NaN, dc=NaN, dcp=NaN) | ||
| results = process_each_job(study, default_result) do job, setup | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This |
||
| (; E, rho, T, npyz) = setup | ||
| Δx = 0.002 / npyz | ||
|
|
||
| # ... postprocessing code for each job (see sections 3.2-3.3) ... | ||
|
|
||
| return (; c_0, c_w, dc, dcp) | ||
| end | ||
| ``` | ||
|
|
||
|
|
||
| #### 3.2 Identify irrelevant data | ||
|
|
||
| Now, invalid or irrelevant data that is not to be processed further is collected. | ||
| For this purpose, another named tuple `default_exp_ret` is defined as the result structure. The function `process_each_export` iterates over the stored export data of the job and then stores only the relevant results in `res`. | ||
|
|
||
| ```julia | ||
| default_exp_ret = (; time=NaN, wave_position=NaN, amplitude_ux=NaN) | ||
| res = process_each_export(job, default_exp_ret) do r0, r, id | ||
| t = first(r[:time]) | ||
| t < 1.5T && return default_exp_ret | ||
| ymax = @views maximum(r0[:position][2, :]) | ||
| pids = findall(eachcol(r0[:position])) do point | ||
| isapprox(point[2], ymax; atol=1.01Δx/2) | ||
| end | ||
| û, pids_id = @views findmax(r[:displacement][1, pids]) | ||
| x̂ = r[:position][1, pids[pids_id]] | ||
| return (; time=t, wave_position=x̂, amplitude_ux=û) | ||
| end | ||
| ``` | ||
|
|
||
|
|
||
| #### 3.3 Transformation of the results | ||
|
|
||
| Now, from the results stored in `res`, the vectors of the fields (`time`, `wave_position`, `amplitude_ux`) are collected in a NamedTuple, unpacked into local vectors, and the indices of the non-NaN entries are determined with `findall` so that only valid measurement points are used later. | ||
|
|
||
| ```julia | ||
| allres = (; (k => getfield.(res, k) for k in keys(default_exp_ret))...) | ||
| (; time, wave_position, amplitude_ux) = allres | ||
| idxs = findall(x -> !isnan(x), time) | ||
| ``` | ||
|
|
||
|
|
||
|
|
||
| #### 3.4 Calculate and display the values | ||
|
|
||
| Now the actual values can be calculated and displayed: | ||
|
|
||
| ```julia | ||
| c_0 = sqrt(E / rho) | ||
| c_w = calc_velocity(time[idxs], wave_position[idxs], amplitude_ux[idxs]) | ||
| dc = c_w - c_0 | ||
| dcp = 100 * dc / c_0 | ||
|
|
||
| @mpiroot begin | ||
| bold = true | ||
| simname = basename(job.options.root) | ||
| printstyled("\nRESULTS FOR SIMULATION: `$(simname)`:\n"; bold) | ||
| printstyled(@sprintf("c_0 = %8.2f m/s\n", c_0); color=:green, bold) | ||
| printstyled(@sprintf("c_w = %8.2f m/s\n", c_w); color=:blue, bold) | ||
| printstyled(@sprintf("Δc = %8.2f m/s (%.3f %%)\n", dc, dcp); color=:red, bold) | ||
| end | ||
| ``` | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this file should not be included. It is not used inside the documentation and just a reference.