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

Fixes to domain decomposition, non-scalar variable updates #110

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
23 changes: 20 additions & 3 deletions ext/JutulMakieExt/mesh_plots.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,28 @@ function Jutul.plot_mesh_impl!(ax, m;
has_face_filter = !isnothing(faces)
has_bface_filter = !isnothing(boundaryfaces)
if has_cell_filter || has_face_filter || has_bface_filter
keep_cells = Dict{Int, Bool}()
keep_faces = Dict{Int, Bool}()
keep_bf = Dict{Int, Bool}()

if eltype(cells) == Bool
@assert length(cells) == number_of_cells(m)
cells = findall(cells)
end
if has_cell_filter
for c in cells
keep_cells[c] = true
end
end
if eltype(faces) == Bool
@assert length(faces) == number_of_faces(m)
faces = findall(faces)
end
if has_face_filter
for f in faces
keep_faces[f] = true
end
end
if eltype(boundaryfaces) == Bool
@assert length(boundaryfaces) == number_of_boundary_faces(m)
boundaryfaces = findall(boundaryfaces)
Expand All @@ -43,6 +57,9 @@ function Jutul.plot_mesh_impl!(ax, m;
nf = number_of_faces(m)
boundaryfaces = deepcopy(boundaryfaces)
boundaryfaces .+= nf
for f in boundaryfaces
keep_bf[f] = true
end
end
ntri = size(tri, 1)
keep = fill(false, ntri)
Expand All @@ -53,13 +70,13 @@ function Jutul.plot_mesh_impl!(ax, m;
tri_tmp = tri[i, 1]
keep_this = true
if has_cell_filter
keep_this = keep_this && cell_ix[tri_tmp] in cells
keep_this = keep_this && haskey(keep_cells, cell_ix[tri_tmp])
end
if has_face_filter
keep_this = keep_this && face_ix[tri_tmp] in faces
keep_this = keep_this && haskey(keep_faces, face_ix[tri_tmp])
end
if has_bface_filter
keep_this = keep_this && face_ix[tri_tmp] in boundaryfaces
keep_this = keep_this && haskey(keep_bf, face_ix[tri_tmp])
end
keep[i] = keep_this
end
Expand Down
22 changes: 15 additions & 7 deletions ext/JutulMakieExt/performance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,22 @@ function Jutul.plot_cumulative_solve!(f, allreports, dt = nothing, names = nothi
c = colors[mod(i-1, n_rep)+1]
data_i = get_data(r_rep[i])
push!(alldata, data_i)
lines!(ax, t[i], data_i,
label = names[i],
linewidth = linewidth,
color = c,
linestyle = get_linestyle(i);
kwarg...)
lstyle = get_linestyle(i)
skip_line = ismissing(lstyle)
if !skip_line
lines!(ax, t[i], data_i,
label = names[i],
linewidth = linewidth,
color = c,
linestyle = lstyle;
kwarg...)
end
if scatter_points
scatter!(ax, t[i], data_i, color = c)
if skip_line
scatter!(ax, t[i], data_i, color = c, label = names[i])
else
scatter!(ax, t[i], data_i, color = c)
end
end
end
if length(r_rep) > 1 && !names_missing && legend
Expand Down
2 changes: 1 addition & 1 deletion src/WENO/WENO.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ module WENO
r::WENOHalfFaceDiscretization{D, N, R};
do_clamp = false,
threshold = 0.0,
epsilon = 1e-10
epsilon = 1e-7
) where {D, N, R}
@assert D == N-1
return new{D, N, R}(l, r, do_clamp, threshold, epsilon)
Expand Down
5 changes: 5 additions & 0 deletions src/dd/finite_volume_map.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ function map_to_active(V, domain, m::FiniteVolumeGlobalMap, ::Cells)
# return filter(i -> m.cell_is_boundary[i], V)
end

function map_ij_to_active(I, J, domain, m::FiniteVolumeGlobalMap, e)
# At the moment only cells can have inactive status
return (I, J)
end

function map_ij_to_active(I, J, domain, m::FiniteVolumeGlobalMap, ::Cells)
n = length(I)
@assert n == length(J)
Expand Down
2 changes: 1 addition & 1 deletion src/simulator/config.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Negative values disable output. The interpretation of this number is subject to

# IO options
add_option!(cfg, :output_path, nothing, "Path to write output. If nothing, output is not written to disk.", types = Union{String, Nothing})
add_option!(cfg, :in_memory_reports, 5, "Limit for number of reports kept in memory if output_path is provided.", types = Int)
add_option!(cfg, :in_memory_reports, 10, "Limit for number of reports kept in memory if output_path is provided.", types = Int)
add_option!(cfg, :report_level, 0, "Level of information stored in reports when written to disk.", types = Int)
add_option!(cfg, :output_substates, false, "Store substates (between report steps) as field on each state.", types = Bool)

Expand Down
2 changes: 1 addition & 1 deletion src/simulator/simulator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ function perform_step_check_convergence_impl!(report, prev_report, storage, mode
converged = false
e = NaN
t_conv = @elapsed begin
if iteration == config[:max_nonlinear_iterations]
if iteration == config[:max_nonlinear_iterations]+1
tf = config[:tol_factor_final_iteration]
else
tf = 1
Expand Down
38 changes: 33 additions & 5 deletions src/timesteps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,37 @@ function pick_next_timestep(sel::VariableChangeTimestepSelector, sim, config, dt
return linear_timestep_selection(x, x0, x1, dt0, dt1)
end

"""
sel = LimitByFailedTimestepSelector(num = 10, factor = 0.9)

Limit the timestep by the shortest of `num` failed timesteps, reducing the
timestep by `factor` multiplied by the shortest failed timestep. If no
time-steps failed during the last `num` steps, the timestep is not changed.
"""
Base.@kwdef struct LimitByFailedTimestepSelector <: AbstractTimestepSelector
num::Int = 10
factor::Float64 = 0.9
end

function pick_next_timestep(sel::LimitByFailedTimestepSelector, sim, config, dt_prev, dT, forces, reports, current_reports, step_index, new_step)
R = successful_reports(reports, current_reports, n = sel.num, success = r -> true)
dt = dT
for rep in R
if !rep[:success]
dt = min(dt, rep[:dt]*sel.factor)
end
end
return dt
end

"""
successful_reports(old_reports, current_reports, step_index, n = 1)

Get the `n` last successful solve reports from all previous reports
(old_reports) and the current ministep set.
(old_reports) and the current ministep set. You can optionally provide a
function that replaces the default definition of `success=r->r[:success]`.
"""
function successful_reports(old_reports, current_reports, step_index, n = 1)
function successful_reports(old_reports, current_reports, step_index, n = 1; success = r -> r[:success])
out = similar(current_reports, 0)
if isfinite(n)
sizehint!(out, n)
Expand All @@ -165,11 +189,15 @@ function successful_reports(old_reports, current_reports, step_index, n = 1)
if step == step_index
reports = current_reports
else
report = old_reports[step]
if ismissing(report)
continue
end
reports = old_reports[step][:ministeps]
end

for r in Iterators.reverse(reports)
if !ismissing(r) && r[:success]
if !ismissing(r) && success(r)
push!(out, r)
if length(out) >= n
return out
Expand All @@ -187,12 +215,12 @@ Get last n successful reports starting at the end of `step` and reversing
backwards until `n` values have been found. `n` can be set to `Inf` to produce
all successful reports.
"""
function successful_reports(reports, current_reports = missing; step = length(reports)+1, n = 1)
function successful_reports(reports, current_reports = missing; step = length(reports)+1, n = 1, kwarg...)
if ismissing(current_reports)
step = clamp(step, 1, length(reports))
current_reports = reports[step][:ministeps]
end
return successful_reports(reports, current_reports, step, n)
return successful_reports(reports, current_reports, step, n; kwarg...)
end

"""
Expand Down
68 changes: 39 additions & 29 deletions src/variables/utils.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const MINIMUM_SAT_RELAX = 1e-6
const MINIMUM_SAT_RELAX = 1e-3
"""
Number of entities (e.g. Cells, Faces) a variable is defined on.
By default, each primary variable exists on all cells of a discretized domain
Expand Down Expand Up @@ -370,6 +370,8 @@ function update_primary_variable!(state, p::FractionVariables, state_symbol, mod
unit_sum_update!(s, p, model, dx, w)
end

unit_update_preserve_direction(::FractionVariables) = true

function unit_sum_update!(s, p, model, dx, w, entity = Cells())
nf, nu = value_dim(model, p)
abs_max = absolute_increment_limit(p)
Expand All @@ -380,7 +382,7 @@ function unit_sum_update!(s, p, model, dx, w, entity = Cells())
if nf == 2
unit_update_pairs!(s, dx, active_cells, minval, maxval, abs_max, w)
else
if true
if unit_update_preserve_direction(p)
# Preserve direction
unit_update_direction!(s, dx, nf, nu, active_cells, minval, maxval, abs_max, w)
else
Expand Down Expand Up @@ -418,28 +420,32 @@ function unit_update_direction_local!(s, active_ix, full_cell, dx, nf, nu, minva

bad_update = w <= MINIMUM_SAT_RELAX
if bad_update
w = w0
end
@inbounds for i in 1:(nf-1)
s[i, full_cell] += w*dx[i, active_ix]
end
@inbounds s[nf, full_cell] += w*dlast0
if bad_update
# Dampening is tiny, update and renormalize instead
tot = 0.0
@inbounds for i in 1:nf
s_i = s[i, full_cell]
sat = clamp(value(s_i), minval, maxval)
tot += sat
s_i = replace_value(s_i, sat)
s[i, full_cell] = s_i
# It was not possible to find a reasonable dampening factor.
# We instead go to the magnitude-preserving version.
unit_update_magnitude_local!(s, active_ix, full_cell, dx, nf, nu, minval, maxval, abs_max)
else
@inbounds for i in 1:(nf-1)
s[i, full_cell] += w*dx[i, active_ix]
end
@inbounds for i = 1:nf
s_i = s[i, full_cell]
s_i = replace_value(s_i, value(s_i)/tot)
s[i, full_cell] = s_i
@inbounds s[nf, full_cell] += w*dlast0
if bad_update
# Dampening is tiny, update and renormalize instead
tot = 0.0
@inbounds for i in 1:nf
s_i = s[i, full_cell]
sat = clamp(value(s_i), minval, maxval)
tot += sat
s_i = replace_value(s_i, sat)
s[i, full_cell] = s_i
end
@inbounds for i = 1:nf
s_i = s[i, full_cell]
s_i = replace_value(s_i, value(s_i)/tot)
s[i, full_cell] = s_i
end
end
end
return s
end

function unit_update_pairs!(s, dx, active_cells, minval, maxval, abs_max, w)
Expand All @@ -456,18 +462,19 @@ function unit_update_pairs!(s, dx, active_cells, minval, maxval, abs_max, w)
end

function unit_update_magnitude!(s, dx, nf, nu, active_cells, minval, maxval, abs_max)
for cell in active_cells
unit_update_magnitude_local!(s, cell, dx, nf, nu, minval, maxval, abs_max)
for active_ix in eachindex(active_cells)
cell = active_cells[active_ix]
unit_update_magnitude_local!(s, active_ix, cell, dx, nf, nu, minval, maxval, abs_max)
end
end

function unit_update_magnitude_local!(s, cell, dx, nf, nu, minval, maxval, abs_max)
function unit_update_magnitude_local!(s, ix, cell, dx, nf, nu, minval, maxval, abs_max)
# First pass: Find the relaxation factors that keep all fractions in [0, 1]
# and obeying the maximum change targets
dlast0 = 0
dlast0 = zero(eltype(dx))
@inbounds for i = 1:(nf-1)
v = value(s[i, cell])
dv = dx[cell + (i-1)*nu]
dv = dx[i, ix]
dv = choose_increment(v, dv, abs_max, nothing, minval, maxval)
s[i, cell] += dv
dlast0 -= dv
Expand All @@ -476,12 +483,15 @@ function unit_update_magnitude_local!(s, cell, dx, nf, nu, minval, maxval, abs_m
dlast = choose_increment(value(s[nf, cell]), dlast0, abs_max, nothing, minval, maxval)
s[nf, cell] += dlast
if dlast != dlast0
# Need to renormalize since the last value was not within bounds.
t = 0.0
for i = 1:nf
@inbounds t += s[i, cell]
# Note: Careful to handle AD values correctly here.
@inbounds t += value(s[i, cell])
end
for i = 1:nf
@inbounds s[i, cell] /= t
@inbounds for i = 1:nf
s_i = s[i, cell]
s[i, cell] = replace_value(s_i, clamp(value(s_i), minval, maxval)/t)
end
end
end
Expand Down
Loading