-
Notifications
You must be signed in to change notification settings - Fork 38
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
[New Miniapp] Time-varying pressure source for acoustic2D #42
Comments
Thanks @alexpattyn for your suggestion. I'd say the goal of the miniapps is exactly to feature domain specific examples on how to implement and leverage ParallelStencil (as this may often be good documentation forgetting other folks started using it). Regarding your addition suggestion: form my point of view it would be valuable to have a version of the acoustic miniapp featuring time varying source. I was actually thinking if it would make sense to add a new version of the acoustic apps that would include both the time-varying source and absorbing boundaries (since you suggested working on an implementation in Discourse) The question I'd like @omlins thoughts on are:
@parallel_indices (ix,iy) function add_source!(P::Data.Array, Signal::Data.Array, it::Int)
if (ix<=size(P, 1) && iy<=size(P, 2)) P[nx÷2, ny÷2] = Signal[it] end # Set source signal value
return
end
# [...]
freq = 1.0 / dt / 5.0 # divide by 5 to stay below the nyquist limit of the grid's sampling frequency
trange = range(0,2pi,length=nt)
amp = 1.0
Signal = Data.Array(amp*sin.(freq*trange))
# [...]
# Time loop
for it = 1:nt
@parallel add_source!(P, Signal, it)
@parallel compute_V!(Vx, Vy, P, dt, ρ, dx, dy)
@parallel compute_P!(P, Vx, Vy, dt, k, dx, dy)
# Visualisation
end
Upon @omlins feedback, you could draft a PR adding the miniapp version(s) we decided upon for review (including the corresponding entries in the README). |
Thanks @alexpattyn for your intentions to create a mini-app. I share @luraess view that mini-apps should solve relevant problems from different domains and mini-apps will often be specific to some domains. @luraess noted:
I totally believe that it would make sense to have these two things in the same code as we certainly don't want to have a large amount of mini-apps that differ only slightly; that would not be very useful. That said, it would be great if your mini-app would include different commonly used "elements" typically found in your domain!
Yes, absolutely, that will make them much more relevant. I think this is fundamental.
That should probably not matter for performance as long as you set the source only in grid point. To conclude, @alexpattyn , we would very much appreciate a PR with a mini-app (in 2-D, 3-D and multi-XPU) as discussed above. :) |
Sounds good! I would think two good examples from my field would be:
The time-varying source and sensors are easy enough to implement, but I don't have much experience with integrating a PML. It looks like I can modify the existing acoustic2D mini-app and base it on k-Wave: MATLAB toolbox for the simulation |
That sounds great @alexpattyn. Most valuable would certainly be to have time-varying source and PML within a single code. Output could be a double panel figure with forward simulation evolution on one panel and sensor arrays output on the other panel.
Indeed, PML may be the tricky bit but would also be a very nice addition. Feel free to ping us when you have a 2D prototype. |
A brief update: Updated the two equations @parallel function compute_V!(Vx::Data.Array, Vy::Data.Array, P::Data.Array, αx::Data.Array, αy::Data.Array, dt::Data.Number, ρ::Data.Number, dx::Data.Number, dy::Data.Number)
@inn(Vx) = @inn(Vx) - dt*(1/ρ*@d_xi(P)/dx + @inn(αx)*@inn(Vx))
@inn(Vy) = @inn(Vy) - dt*(1/ρ*@d_yi(P)/dy + @inn(αy)*@inn(Vy))
return
end @parallel function compute_P!(P::Data.Array, Vx::Data.Array, Vy::Data.Array, dt::Data.Number, ρ::Data.Number, dx::Data.Number, dy::Data.Number)
@all(P) = @all(P) - dt*(ρ*(@d_xa(Vx)/dx + @d_ya(Vy)/dy)+(@all(αx) + @all(αy))*@all(P))
return
end I got a little confused on how to break the pressure field into x and y components as described in the paper I linked above. I tried taking the It seems that the PML causes some back-reflection itself, so I will have to look into this a little further. I know sometimes people define the PML as a gradient of attenuation to limit that back-reflection but I have to test that out. As far as I am aware k-wave doesn't do this, and I would prefer to avoid that additional complexity. Once that is finished I have to clean my 2D code up and can submit it for review! @omlins @luraess One thing I wanted to ask was is there a reason to use |
Thanks @alexpattyn for sharing those details. Your absorbing boundaries implementation looks promising. As far as I remember from early experiments, the PML approach should ideally not generate any reflections (while the less formal "sponge" approach would). In the Cox et al. paper you refer to, it seems they use the single parameter α (as you in the code snippet) to absorb at the boundaries. If you didn't yet, it may be worth trying to define α as specially increasing within the absorbing layer (in e.g. the log space). Also, there may be quite some literature on PML coming from geophysics. Also, I wouldn't split the pressure update as it's not a vector field; there is only one pressure.
The reason is that we are using a staggered grid; pressure is defined in the cell centre, while velocity is defined, like a flux, at cell faces. For this reason, one needs different array sizes (independent from the boundary condition) to get sizes to match upon taking the derivatives.
Sure! And then we should do the 3D multi-XPU version based on that 🙂 |
Another UpdateI made the PML a gradient between 0 and 1 and this seems to yield better results. I still get some back-reflections, but they are orders of magnitude lower in amplitude. I will continue to take a closer look at this and then compare it against k-wave to see if I get similar results - I can also benchmark it against their OpenMP C++ code. Acoustic 2D with PMLAcoustic 2D without PML
Definitely! I have a couple of NVIDIA cards I can test it against to see how the GPU/XPU version runs. |
Thanks for the update. I guess the making the absorbing layer gradually absorbing is indeed one way to go. I am still wondering wether this approach is then not rather spine boundaries as from what I recall PML should be, as the name suggests, perfectly matched (i.e. provide the exact correction).
I'd guess doing some kind of benchmarking activity would be good just to ensure one has a solid approach.
That's be great 🙂 |
From the k-wave documentation:
They then go on to say that the attenuation coefficient should vary spatially, and they use the equation below: So it looks like we are on the right track still! Edit: They also say after discussing the specifics of the PML:
So I suppose it should be up to the user to determine their threshold for accuracy - i.e. we will never have a perfect PML ironically. Once I get their implementation of the PML working I would consider that part done. |
That's interesting, thanks for reporting. I'd say that indeed, if the errors are sufficiently small we could go with it. Would be good, as you proposed, to quantify that briefly in a kind of benchmark. |
@luraess Sorry for disappearing on this. Had a busy end of the fall semester and start of this semester. Interested in completing this issue though. How would you recommend quantifying the error? Taking the average pressure within the non-PML region after the wave enters the PML? Ideally the pressure in the non-PML region would be zero, but it seems this is not possible based on the docs from k-wave. |
Thanks @alexpattyn for resuming this. Good question regarding the error quantification. I guess the real accurate approach may be to quantify the energy loss through the PML and ensure that most of the energy is indeed absorbed in the PML-region. I don't know however if this level of complexity is needed here. It may indeed be sufficient to proceed as you suggest
You could maybe try the above one for various cases (including optimal and less optimal absorbing parameters) to get an idea about how relevant this approach could be. I guess it would make sense the pressure error to be smallest for optimal PML absorbing params. |
Reviewing k-waves docs, they quantified the performance of the PML by looking at the change in amplitude of the transmitted and reflected wave. From my earlier comments \alpha_max = A c/dx; where A = maximum attenuation, c = sound speed, and dx = spatial discretization. When A = 4 I am seeing ~37dB drop in the reflected signal, where dB drop = 20*log10(P/P0) | P = max reflected amplitude and P0 = max amplitude. I'll continue to look into this. |
I saw a paper from Yuan et al where to compare the effects of a PML verses Mur's second order boundary condition. They'd defined some error function that looks at the relative difference between the acoustic field with a boundary condition and one without (where the forward model is stopped before reflection occur). Which I implemented as: Error += @. 10*log10((Pₜᵣᵤₑ - Pₚₘₗ)^2/Pₜᵣᵤₑ^2) Given this I got the results below: So I think we are good with the current PML implementation. I can add a comment in the code that the user should fine-tune the PML parameters for their particular applications. Unless there are other comments I can start to prepare a PR. |
Hi @alexpattyn, thanks for your new addition. I'd say your latest error analysis makes sense and serves the purpose. One thing I was wondering is why the setup is not fully symmetric? Do I miss something?
That sounds reasonable to me, unless @omlins has something else to add prior to that. Note however that ParallelStencil is undergoing some refactoring, so I there are two options:
In all cases, thanks for your contribution! |
Hey @luraess,
You are referring to the "purple" diagonal in the error heatmap? That was something I was wondering as well. I'll try to investigate that a bit further. Considering there is a refactoring going on I'll hold off on the PR for now. Additionally, I would also like to get an ultrasound simulation going with realistic physical properties (e.g. domain of 220 mm x 220 mm), however I am getting stability issues that I need to look at. But no problem! It is helpful for my own research project. I just wish I had more time to spend on this. But will the refactor include AMD GPU support? 😀 |
Yes, it would be good to see that if the entire configuration is symmetric, then an asymmetry may be a hint for a minor onset somewhere.
We are on it, yes 😄 |
What do you mean here? Like stability issues or a model mismatch?
Fantastic! I have a Radeon VII ready to be benchmarked when the time comes. 😄 |
Not really, rather something like the initial perturbation not being fully centred, or some indexing bug - something maybe super minor that would make the configuration non-symmetric.
Super! |
Not sure if you want to avoid domain specific miniapps, but I am working towards modifying the acoustic 2D miniapp for ultrasound and photoacoustic modeling. Currently I just played around with getting a time-varying source working.
My current implementation just sets the pressure at a given pixel based on some source signal vector.
I can clean my code up a bit and submit it as an acoustic2D with time varying source miniapp, but I wanted to see if this would be a recommended way of implementing a time-varying source? Or if this poses obvious performance penalties that users shouldn't be exposed to.
The text was updated successfully, but these errors were encountered: