Skip to content

Commit

Permalink
started adding extension for interpolating ExtendableFEM vectors into…
Browse files Browse the repository at this point in the history
… edgevelocities

added basic dispatch structure for ExtendableFEMBase edgevelocities interpolation

adjusted integration so it runs through and produces a result now
  • Loading branch information
Da-Be-Ru authored and pjaap committed Oct 10, 2024
1 parent e08f5ff commit 1358289
Show file tree
Hide file tree
Showing 3 changed files with 267 additions and 4 deletions.
7 changes: 7 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,19 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"

[weakdeps]
ExtendableFEMBase = "12fb9182-3d4c-4424-8fd1-727a0899810c"

[extensions]
VoronoiFVMExtendableFEMBaseExt = "ExtendableFEMBase"

[compat]
BandedMatrices = "0.17,1"
Colors = "0.12"
CommonSolve = "0.2"
DiffResults = "1"
DocStringExtensions = "0.8,0.9"
ExtendableFEMBase = "0.7.0"
ExtendableGrids = "1.9.2"
ExtendableSparse = "1.5.1"
ForwardDiff = "0.10.35"
Expand Down
256 changes: 256 additions & 0 deletions ext/VoronoiFVMExtendableFEMBaseExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
module VoronoiFVMExtendableFEMBaseExt

using VoronoiFVM
using ExtendableFEMBase
using ExtendableGrids

id(u) = (u, Identity)

function iscloser(pint,p1,p2,eps)
return norm(pint-p2)<norm(p2-p1)-eps
end

"""
This is the FEVectorBlock with lots of info from ExtendableFEMBase
to execute integration along given segments
"""
struct AugmentedFEVectorBlock
vblock::FEVectorBlock

seg_integrator
point_evaluator
cellfinder
flowgrid
end

function multiply_r(result, input, qpinfo)
x = qpinfo.x
result .= input * x[1]
return nothing
end

function prepare_segment_integration(vel; axisymmetric=false, reconst=false, kwargs...)
flowgrid = vel.FES.xgrid

# reference mappings not implemented for other coord types
cartesian!(flowgrid)

if axisymmetric
if reconst
seg_integrator = SegmentIntegrator(Edge1D, [id(1)])
else
seg_integrator = SegmentIntegrator(Edge1D, multiply_r, [id(1)]; bonus_quadorder=1)
end
else
seg_integrator = SegmentIntegrator(Edge1D, [id(1)])
end

initialize!(seg_integrator, [vel])
point_evaluator = PointEvaluator([id(1)], [vel])

cellfinder = CellFinder(flowgrid)

if axisymmetric
circular_symmetric!(flowgrid)
end

return seg_integrator, point_evaluator, cellfinder, flowgrid
end

function VoronoiFVM.edgevelocities(grid, vel::FEVectorBlock; kwargs...)
axisymmetric = grid[CoordinateSystem] <: Cylindrical2D ? true : false
seg_integrator, point_evaluator, cf, flowgrid = prepare_segment_integration(vel; axisymmetric, kwargs...)
aug_fevec_block = AugmentedFEVectorBlock(vel, seg_integrator, point_evaluator, cf, flowgrid)
velovec = VoronoiFVM.edgevelocities(grid, aug_fevec_block; axisymmetric,kwargs...)

if axisymmetric
circular_symmetric!(flowgrid)
end

return velovec
end

function VoronoiFVM.integrate(::Type{<:Cartesian2D}, p1, p2, hnormal, aug_vec_block::AugmentedFEVectorBlock; kwargs...)
_integrate_along_segments(p1, p2, hnormal, aug_vec_block; kwargs...)
end

function VoronoiFVM.integrate(::Type{<:Cylindrical2D}, p1, p2, hnormal, aug_vec_block::AugmentedFEVectorBlock; kwargs...)
_integrate_along_segments(p1, p2, hnormal, aug_vec_block; kwargs...)
end

function _integrate_along_segments(p1, p2, hnormal, aug_vec_block::AugmentedFEVectorBlock; interpolate_eps=1.0e-12, axisymmetric = false, kwargs...)

edge_length = norm(p1 - p2, 2)
avg_r = (p1[1]+p2[1])/2
bp1 = zeros(3)
CF = aug_vec_block.cellfinder
icell::Int = gFindLocal!(bp1, CF, p1; eps=interpolate_eps)
if edge_length interpolate_eps
point_evaluator = aug_vec_block.point_evaluator
evaluate_bary!(p2, point_evaluator, bp1, icell)
if axisymmetric
return dot(p2, hnormal)/(avg_r)
else
return dot(p2, hnormal)
end
end

SI = aug_vec_block.seg_integrator


xCellFaces = CF.xCellFaces
xFaceCells = CF.xFaceCells
facetogo = CF.facetogo
cx = CF.cx
icell_new = icell
prevcell = icell
L2G = CF.L2G4EG[1]
L2Gb = L2G.b
invA = CF.invA

result = zeros(Float64, 2)
summand = zeros(Float64, 2)
bp2 = zeros(Float64, 3)
pint = zeros(Float64, 2)
bpint = zeros(Float64, 3)
bary = [1 / 3, 1 / 3, 1 / 3]
t = 0.0

p1_temp = zeros(Float64, 3)

function calc_barycentric_coords!(bp, p)
for j = 1:2
cx[j] = p[j] - L2Gb[j]
end

fill!(bp, 0)
for j = 1:2, k = 1:2
bp[k] += invA[j, k] * cx[j]
end
ExtendableGrids.postprocess_xreftest!(bp, CF.xCellGeometries[icell])
end

i = 1
#@info "icell=$icell"
#@info "p1=$p1, p2=$p2"

while (true)
# first compute the barycentric coordinates of
# p1,p2

#@info "icell = $(icell), step=$i"
#@info "p1=$(p1), p2=$(p2)"
# update local 2 global map
L2G = CF.L2G4EG[1]
update_trafo!(L2G, icell)
L2Gb = L2G.b

mapderiv!(invA, L2G, p1)

calc_barycentric_coords!(bp1, p1)
calc_barycentric_coords!(bp2, p2)

# if p1 is a node of a triangle, start with
# a cell containing p1 in the direction of (p2-p1)
if count(<=(interpolate_eps), bp1) == 2 # 10^(-13)
p1_temp[1:2] = p1 + 10 * interpolate_eps * (p2 - p1)
icell_new = gFindLocal!(bp1, CF, p1_temp[1:2]; eps=10 * interpolate_eps, icellstart=icell)
if icell_new == 0
@warn "icell_new=0!"
end
if icell_new != icell# && icell_new!=0
icell = icell_new
continue
end
end

# push p1 a little towards the triangle circumcenter
# to avoid it being situated on an edge or node of the
# flowgrid
# (to avoid being stuck on an edge if (p2-p1) is
# on the edge
bp1 .+= interpolate_eps .* (bary - bp1)
eval_trafo!(p1, L2G, bp1)

(λp2min, imin) = findmin(bp2)

#@info "bp1=$(bp1), bp2=$(bp2), λp2min=$(λp2min)"

# if λp2min≥0, then p2 is inside icell and we can simply add the
# integral across the line segment between p1 and p2 to the result

# if not, then p2 is outside of icell and we try to determine
# pint which is the point where icell intersects the line segment
# [p1,p2] - since pint should be on the boundary of icell,
# at least one barycentric coordinate (stored in bpint) should
# be zero yielding an expression for the line segment parameter t.
# this is not necessarily the previous imin and we have to check
# all triangle edges for if going towards that edge actually takes us
# closer to p2

if λp2min -interpolate_eps
SI.integrator(summand, Array{Vector{Float64}}([p1, p2]), [bp1, bp2], icell)
result += summand
break
else
# calculate intersection point with corresponding edge
imin = 0
t = 1.0 + interpolate_eps
pint .= p1
closestimin = 1
closestdist = Inf
p1_temp .= 0
while !iscloser(pint, p1, p2, interpolate_eps) || (any(bpint .<= -interpolate_eps) || any(bpint .>= 1 + interpolate_eps)) || norm(bpint - bp1) <= interpolate_eps # check if pint takes us closer to p2 and if bpint is inside the cell *and* if we actually moved with pint from p1
imin += 1
if imin == 4
imin = closestimin
bpint .= p1_temp
break
end
#@info "imin = $imin"
t = bp1[imin] / (bp1[imin] - bp2[imin])
#@info "t=$t"
bpint = bp1 + t * (bp2 - bp1)
#@info "bpint = $bpint"
eval_trafo!(pint, L2G, bpint)
#@info "pint=$pint"
if norm(pint - p2) < closestdist && ((all(bpint .>= -interpolate_eps) && all(bpint .<= 1 + interpolate_eps)))
closestimin = imin
closestdist = norm(pint - p2)
p1_temp .= bpint
end
end
eval_trafo!(pint, L2G, bpint)
#@info "pint = $pint"

# add integral term
SI.integrator(summand, Array{Vector{Float64}}([p1, pint]), [bp1, bpint], icell)
result += summand
#@info "segment part: $summand"
# proceed to next cell along edge of smallest barycentric coord
prevcell = icell
icell = xFaceCells[1, xCellFaces[facetogo[1][imin], icell]]
icell = icell == prevcell ? xFaceCells[2, xCellFaces[facetogo[1][imin], icell]] : icell

#@info "icell = $icell"
#@info "bpint = $bpint"
#if any(bpint.<=-1.0e-10)
# @warn "negative bpint coord!"
#end
#icell=gFindLocal!(bpint,CF,pint;icellstart=icell)
#@info "icell_after = $(icell)"
#@info "bpint_after = $(bpint)"

p1 .= pint
end
i += 1
end

if axisymmetric
return dot(result,hnormal)/(avg_r*edge_length)
else
return dot(result,hnormal)/edge_length
end
end

end
8 changes: 4 additions & 4 deletions src/vfvm_formfactors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ end
#
# TODO: this should be generalized for more quadrules
#
function integrate(::Type{<:Cartesian2D}, coordl, coordr, hnormal, velofunc)
function integrate(::Type{<:Cartesian2D}, coordl, coordr, hnormal, velofunc; kwargs...)
wl = 1.0 / 6.0
wm = 2.0 / 3.0
wr = 1.0 / 6.0
Expand All @@ -337,7 +337,7 @@ function integrate(::Type{<:Cartesian2D}, coordl, coordr, hnormal, velofunc)
return (wl * vxl + wm * vxm + wr * vxr) * hnormal[1] + (wl * vyl + wm * vym + wr * vyr) * hnormal[2]
end

function integrate(::Type{<:Cylindrical2D}, coordl, coordr, hnormal, velofunc)
function integrate(::Type{<:Cylindrical2D}, coordl, coordr, hnormal, velofunc; kwargs...)
wl = 1.0 / 6.0
wm = 2.0 / 3.0
wr = 1.0 / 6.0
Expand Down Expand Up @@ -367,7 +367,7 @@ $(SIGNATURES)
Project velocity onto grid edges,
"""
function edgevelocities(grid, velofunc)
function edgevelocities(grid, velofunc; kwargs...)
@assert dim_space(grid) < 3

cn = grid[CellNodes]
Expand Down Expand Up @@ -404,7 +404,7 @@ function edgevelocities(grid, velofunc)
p2 .= 0.5 * (coord[:, K] + coord[:, L])
end
hnormal = coord[:, K] - coord[:, L]
velovec[iedge] = integrate(coord_system, p1, p2, hnormal, velofunc)
velovec[iedge] = integrate(coord_system, p1, p2, hnormal, velofunc; kwargs...)
end
end
return velovec
Expand Down

0 comments on commit 1358289

Please sign in to comment.