JuliaPhysics/SolidStateDetectors.jl

Zoomed-in field calculations

leenderthayen opened this issue · 5 comments

Hello,

We'd like to simulate a small part of the geometry of our Silicon detectors close to pixel edges, where we have substantial variation in the impurity density profile. Since the physical dimension of this region is very small compared to the total geometry, performing a regular simulation with extremely high grid density is not feasible. How would one best go about this in your code? I'm aware only of setting the boundary conditions to be set at infinity, is anything else included right now?

Thank you,
Leendert

lmh91 commented

You can also set "reflecting", "periodic" and "fixed" as boundary conditions.
"fixed" means in that case 0.
(I hope all of them work. For the cartesian case we do not have all of them in the tests I believe.)

Right now, "fixed" means that a potential of 0 is assumed at the boundaries.
In the far future, we would like to make an interface so the user
can define the potential on the boundaries of the world via a function.
But this is not high on the priority list I must admit.

Alright, I can try to see where that brings us. Is an unevenly spaced grid also an option? Meaning a higher grid density near the surface versus the bulk, something like a logarithmic grid maybe.

lmh91 commented

Yes, you can define your own grid and pass it to calculate_electric_potential!.

I guess the easiest way to do it would be something like

    T = Float32
    sim = Simulation{T}(SSD_examples[:CGD])
    calculate_electric_potential!(sim, 
        max_refinements = 0, 
        max_n_iterations = 10, 
        init_grid_spacing =  T.((0.01, 0.01, 0.01)), 
    )
    g = sim.electric_potential.grid
    ax1, ax2, ax3 = g.axes
    user_additional_ticks_ax1 = T[0.002123] # here add your ticks of interest
    user_additional_ticks_ax2 = T[0.003123] # here add your ticks of interest
    user_additional_ticks_ax3 = T[0.004123] # here add your ticks of interest
    user_ax1 = typeof(ax1)(ax1.interval, sort(vcat(ax1.ticks, user_additional_ticks_ax1)))
    user_ax2 = typeof(ax2)(ax2.interval, sort(vcat(ax2.ticks, user_additional_ticks_ax2)))
    user_ax3 = typeof(ax3)(ax3.interval, sort(vcat(ax3.ticks, user_additional_ticks_ax3)))
    user_g = typeof(g)((user_ax1, user_ax2, user_ax3))

    calculate_electric_potential!(sim, grid = user_g)

But be aware that convergence is really slow when voxels are extremely streched (not cubic like).
It works, but you might need a hell of a lot iterations in extrem cases.
(You might also have to switch to Float64).

I noticed in your example that the ticks are still constant, although they differ for x,y,z. This would reduce the computational load to one dimension instead of 3, but will still spend the vast majority of it calculating in a region with little to no variation. Is there a way to make axes with non-constant ticks? Looking at the source code for DiscreteAxis.jl, it seems like everything is based on Intervals, which might make this hard?

lmh91 commented

You parse an interval and a vector of ticks to it like I did in my example:

user_ax1 = typeof(ax1)(ax1.interval, sort(vcat(ax1.ticks, user_additional_ticks_ax1)))

typeof(ax1) gives you the correct constructor for the DiscreteAxis depending on your world.
user_additional_ticks_ax1 is a list of ticks where you want your axis to be finer. I just added one dummy extra tick there.