Skip to content
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

Fix the tail issue of the identity operator in TD-MFIE #141

Merged
merged 3 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions examples/tdpmchwt_cq.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using BEAST, LinearAlgebra, CompScienceMeshes, ConvolutionOperators, Printf

# Physical parameters
ϵ, μ = 1.0, 1.0
ϵ′, μ′ = 1.0, 1.0
η, η′ = √(μ/ϵ), √(μ′/ϵ′)

T = BEAST.LaplaceDomainOperator(s::ComplexF64 -> MWSingleLayer3D(s*√(ϵ*μ), -s*√(ϵ*μ), ComplexF64(1/√(ϵ*μ))/s))
K = BEAST.LaplaceDomainOperator(s::ComplexF64 -> MWDoubleLayer3D(s*√(ϵ*μ)))
T′ = BEAST.LaplaceDomainOperator(s::ComplexF64 -> MWSingleLayer3D(s*√(ϵ′*μ′), -s*√(ϵ′*μ′), ComplexF64(1/√(ϵ′*μ′))/s))
K′ = BEAST.LaplaceDomainOperator(s::ComplexF64 -> MWDoubleLayer3D(s*√(ϵ′*μ′)))

Γ = meshsphere(1.0, 0.3)
X = raviartthomas(Γ)
Y = buffachristiansen(Γ)

@hilbertspace k l
@hilbertspace j m

Nt, Δt = 200, 10.0
(A, b, c) = butcher_tableau_radau_2stages()
CQ = StagedTimeStep(Δt, Nt, c, A, b, 30, 1.0001)

duration = 40 * Δt
delay = 60 * Δt
amplitude = 1.0
gaussian = creategaussian(duration, delay, amplitude)
fgaussian = fouriertransform(gaussian)
polarisation, direction = x̂, ẑ
E = planewave(polarisation, direction, gaussian, 1.0)
H = direction × E

BEAST.@defaultquadstrat (T, X⊗CQ, X⊗CQ) BEAST.DoubleNumWiltonSauterQStrat(6, 7, 6, 7, 7, 7, 7, 7)
BEAST.@defaultquadstrat (T′, X⊗CQ, X⊗CQ) BEAST.DoubleNumWiltonSauterQStrat(6, 7, 6, 7, 7, 7, 7, 7)
BEAST.@defaultquadstrat (K, X⊗CQ, X⊗CQ) BEAST.DoubleNumWiltonSauterQStrat(6, 7, 6, 7, 7, 7, 7, 7)
BEAST.@defaultquadstrat (K′, X⊗CQ, X⊗CQ) BEAST.DoubleNumWiltonSauterQStrat(6, 7, 6, 7, 7, 7, 7, 7)

pmchwt = @discretise(η*T[k,j] + η′*T′[k,j] + K[l,j] + K′[l,j]
- K[k,m] - K′[k,m] + 1/η*T[l,m] + 1/η′*T′[l,m] == E[k] + H[l],
k∈X⊗CQ, l∈X⊗CQ, j∈X⊗CQ, m∈X⊗CQ)
je = solve(pmchwt)


# Exact solution
N = NCross()
Nyx = assemble(N, Y, X)
iNyx = inv(Matrix(Nyx))
Zr = zeros(size(iNyx))

δ = timebasisdelta(Δt, Nt)
linform = @discretise(H[k] + E[l], k∈Y⊗δ, l∈Y⊗δ)
rhs = BEAST.assemble(linform.linform, linform.test_space_dict)
j_ext = [iNyx Zr; Zr iNyx] * rhs


# Plot the numerical solutions
using Plots
x = 1e-2 * Δt/3 * [1:1:Nt;]

plt = Plots.plot(
size = (600, 400),
grid = false,
xscale = :identity,
# xlims = (0, 1620),
# xticks = [400, 800, 1200, 1600],
xtickfont = Plots.font(10, "Computer Modern"),
yscale = :log10,
ylims = (1e-15, 1e0),
yticks = [1e-20, 1e-15, 1e-10, 1e-5, 1e0, 1e5],
ytickfont = Plots.font(10, "Computer Modern"),
xlabel = "Time ({\\mu}s)",
ylabel = "Current density intensity (A/m)",
titlefont = Plots.font(10, "Computer Modern"),
guidefont = Plots.font(11, "Computer Modern"),
colorbar_titlefont = Plots.font(10, "Computer Modern"),
legendfont = Plots.font(11, "Computer Modern"),
legend = :topright,
dpi = 300)

Plots.plot!(x, abs.(j_ext[1, :]), label="Exact solution", linecolor=1, lw=1.2)
Plots.plot!(x, abs.(je[1, :]), label="TD-PMCHWT", linecolor=2, lw=1.2)
72 changes: 72 additions & 0 deletions src/timedomain/rkcq.jl
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,75 @@ function assemble(rkcq :: RungeKuttaConvolutionQuadrature,
return ZC

end


struct LaplaceDomainOperator
coeff::ComplexF64
kernel::Any
end

scalartype(op::LaplaceDomainOperator) = ComplexF64

*(a::Number, op::LaplaceDomainOperator) = LaplaceDomainOperator(a*op.coeff, op.kernel)

LaplaceDomainOperator(kernel) = LaplaceDomainOperator(Complex(1.0), kernel)

defaultquadstrat(op::LaplaceDomainOperator, tfs::SpaceTimeBasis, bfs::SpaceTimeBasis) = DoubleNumWiltonSauterQStrat(2,3,6,7,5,5,4,3)

function assemble(op::LaplaceDomainOperator, testfns::SpaceTimeBasis, trialfns::SpaceTimeBasis; quadstrat=defaultquadstrat(op, testfns, trialfns))
laplaceKernel = op.kernel

A = testfns.time.A
b = testfns.time.b
Δt = testfns.time.Δt
Q = testfns.time.zTransformedTermCount
rho = testfns.time.contourRadius
p = length(b) # stage count

test_spatial_basis = testfns.space
trial_spatial_basis = trialfns.space

# Compute the Z transformed sequence.
# Assume that the operator applied on the conjugate of s is the same as the
# conjugate of the operator applied on s,
# so that only half of the values are computed
Qmax = Q>>1+1
M = numfunctions(test_spatial_basis)
N = numfunctions(trial_spatial_basis)
Tz = ComplexF64
Zz = Vector{Array{Tz,2}}(undef,Qmax)
blocksEigenvalues = Vector{Array{Tz,2}}(undef,p)
tmpDiag = Vector{Tz}(undef,p)

for q = 0:Qmax-1
# Build a temporary matrix for each eigenvalue
s = laplace_to_z(rho, q, Q, Δt, A, b)
sFactorized = diagonalizedmatrix(s)
for (i,sD) in enumerate(sFactorized.D)
blocksEigenvalues[i] = op.coeff * assemble(laplaceKernel(sD), test_spatial_basis, trial_spatial_basis, quadstrat=quadstrat)
end

# Compute the Z transformed matrix by block
Zz[q+1] = zeros(Tz, M*p, N*p)
for m = 1:M
for n = 1:N
for i = 1:p
tmpDiag[i] = blocksEigenvalues[i][m,n]
end
D = SVector{p,Tz}(tmpDiag);
Zz[q+1][(m-1)*p.+(1:p),(n-1)*p.+(1:p)] = sFactorized.H * diagm(D) * sFactorized.invH
end
end
end

# return the inverse Z transform
kmax = Q
T = real(Tz)
Z = zeros(T, M*p, N*p, kmax)
for q = 0:kmax-1
Z[:,:,q+1] = real_inverse_z_transform(q, rho, Q, Zz)
end
ZC = ConvolutionOperators.DenseConvOp(Z)

return ZC
end
2 changes: 1 addition & 1 deletion src/timedomain/tdtimeops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ function allocatestorage(op::TensorOperator, test_functions, trial_functions,
tail = zeros(T, M, N)

Nt = numfunctions(temporalbasis(trial_functions))
Z = ConvolutionOperators.ConvOp(data, K0, K1, tail, Nt)
Z = ConvolutionOperators.ConvOp(data, K0, K1, tail, bandwidth)
function store1(v,m,n,k)
if Z.k0[m,n] ≤ k ≤ Z.k1[m,n]
Z.data[k - Z.k0[m,n] + 1,m,n] += v
Expand Down
2 changes: 1 addition & 1 deletion test/test_td_tensoroperator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ using Test
op = Id ⊗ Id
Z = assemble(op, V, U)
A = BEAST.ConvolutionOperators.ConvOpAsArray(Z)
@test size(A) == (1,1,10)
@test size(A) == (1,1,2)
for i in 2:10
@test A[1,1,i] ≈ 0 atol=sqrt(eps(eltype(A)))
end
Expand Down
Loading