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

2D unstructured converter, nonlinear discretizations and improvements to multimodel #90

Merged
merged 50 commits into from
Aug 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
b406585
added global check for multimodel
xavierr Feb 29, 2024
af8d3da
added branching for early stop
xavierr Mar 18, 2024
89fbbc8
changed key name
xavierr May 28, 2024
7e53354
Merge branch 'global_check_for_multimodel' into battmo
xavierr May 28, 2024
85903ca
Merge branch 'main' into battmo
xavierr May 28, 2024
f5ad714
added specialization for multimodel
xavierr Jun 25, 2024
86207ec
Fix to CartesianMesh converter
moyner Aug 4, 2024
5328485
Make MultiModel a bit more concrete
moyner Aug 5, 2024
8bda61e
Improve JutulStorage interface
moyner Aug 5, 2024
287ed0d
Update submodels.jl
moyner Aug 5, 2024
6bc31da
Update core_types.jl
moyner Aug 5, 2024
84d51bd
Clean up submodel_symbols vs submodels_symbols
moyner Aug 5, 2024
d0db78d
Add specialized compiled converter for multimodel
moyner Aug 5, 2024
1ca13c2
Add label to MultiModel and make abstract supertype
moyner Aug 6, 2024
ce4d11e
Merge pull request #84 from sintefmath/multimodel-specialize
moyner Aug 6, 2024
42e515f
Add missing dispatches for composite system
moyner Aug 6, 2024
722b236
Guard against Inf max value for variables in optimization
moyner Aug 6, 2024
19143b7
Work in progress on getting composite adjoints running
moyner Aug 6, 2024
2a25d99
Fix composite bug in sparsity
moyner Aug 7, 2024
f94d1fc
Add a consistency utility for composite models
moyner Aug 7, 2024
fa2b688
composite: Avoid overloading high level sparsity
moyner Aug 7, 2024
770b105
Add specializations to composite system for TPFA
moyner Aug 7, 2024
a323be8
Update models.jl
moyner Aug 8, 2024
d484a5b
Add a converter in objective evaluation
moyner Aug 9, 2024
8edee3c
Fix typo in assert message
moyner Aug 14, 2024
68db7af
Support tuples in CartesianMesh, add test
moyner Aug 15, 2024
9618d03
WIP on adding 2D converters for unstructured mesh
moyner Aug 15, 2024
9c972a0
Reorganize mesh converter tests
moyner Aug 15, 2024
49c2e6b
Simplify 2D volume
moyner Aug 15, 2024
f617c39
Tests pass for 2D geometry
moyner Aug 15, 2024
220783b
meshes: Improve tests and add 1D conversion
moyner Aug 15, 2024
4a61b71
Add plotting to 2D unstructured meshes
moyner Aug 15, 2024
7df9bdd
Fix line edges in 2D
moyner Aug 15, 2024
e38166d
Merge pull request #86 from sintefmath/2d_convert
moyner Aug 15, 2024
1075ae0
Don't use 3D axes for 2D plots
moyner Aug 16, 2024
f06ac0a
plotting of faces and bounderies
hnil Aug 21, 2024
3a89ad9
fixed orientation of boundary faces
hnil Aug 22, 2024
40cc5e6
Nonlinear finite-volume schemes, non-TPFA support, various smaller fi…
moyner Aug 23, 2024
80af4d5
get_1d_interpolator: Handle scalar inputs
moyner Aug 24, 2024
9dc3a93
1d interpolation: Don't mutate
moyner Aug 24, 2024
0e06c99
Update interpolation.jl
moyner Aug 24, 2024
1381f6e
Updates to FVM flux interface
moyner Aug 26, 2024
148b445
Update types.jl
moyner Aug 28, 2024
730e6c8
Fix to submodel for non-defaulted equations
moyner Aug 28, 2024
5b552e7
Use standard interface for subdiscretization in NFVM
moyner Aug 28, 2024
ae8ff08
Add functions for finding cells intersected by piecewise linear curves
moyner Aug 29, 2024
2b56f96
Merge branch 'dev' into battmo
moyner Aug 31, 2024
8da2e01
Merge pull request #92 from sintefmath/battmo
moyner Aug 31, 2024
3925676
Bump version
moyner Aug 31, 2024
35a6edb
Disable assert that triggers on some bad reservoirs
moyner Aug 31, 2024
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
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Jutul"
uuid = "2b460a1a-8a2b-45b2-b125-b5c536396eb9"
authors = ["Olav Møyner <olav.moyner@gmail.com>"]
version = "0.2.35"
version = "0.2.36"

[deps]
AlgebraicMultigrid = "2169fc97-5a83-5252-b627-83903c6c433c"
Expand Down
6 changes: 6 additions & 0 deletions ext/JutulMakieExt/interactive_3d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,12 @@ function basic_3d_figure(resolution = default_jutul_resolution(); z_is_depth = f
return (fig, ax)
end

function basic_2d_figure(resolution = default_jutul_resolution(); z_is_depth = false)
fig = Figure(size = resolution)
ax = Axis(fig[1, 1])
return (fig, ax)
end


function symlog10(x)
# Inspired by matplotlib.scale.SymmetricalLogScale
Expand Down
53 changes: 47 additions & 6 deletions ext/JutulMakieExt/mesh_plots.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,65 @@ function Jutul.plot_mesh_impl(m;
z_is_depth = Jutul.mesh_z_is_depth(m),
kwarg...
)
fig, ax = basic_3d_figure(resolution, z_is_depth = z_is_depth)
if dim(m) == 3
makefig = basic_3d_figure
else
makefig = basic_2d_figure
end
fig, ax = makefig(resolution, z_is_depth = z_is_depth)
p = Jutul.plot_mesh!(ax, m; kwarg...)
display(fig)
return (fig, ax, p)
end

function Jutul.plot_mesh_impl!(ax, m;
cells = nothing,
faces = nothing,
boundaryfaces = nothing,
outer = false,
color = :lightblue,
kwarg...
)
pts, tri, mapper = triangulate_mesh(m, outer = outer)
if !isnothing(cells)
has_cell_filter = !isnothing(cells)
has_face_filter = !isnothing(faces)
has_bface_filter = !isnothing(boundaryfaces)
if has_cell_filter || has_face_filter || has_bface_filter
if eltype(cells) == Bool
@assert length(cells) == number_of_cells(m)
cells = findall(cells)
end
if eltype(faces) == Bool
@assert length(faces) == number_of_faces(m)
faces = findall(faces)
end
if eltype(boundaryfaces) == Bool
@assert length(boundaryfaces) == number_of_boundary_faces(m)
boundaryfaces = findall(boundaryfaces)
end
if has_bface_filter
nf = number_of_faces(m)
boundaryfaces = deepcopy(boundaryfaces)
boundaryfaces .+= nf
end
ntri = size(tri, 1)
keep = [false for i in 1:ntri]
keep = fill(false, ntri)
cell_ix = mapper.indices.Cells
face_ix = mapper.indices.Faces
for i in 1:ntri
# All tris have same cell so this is ok
keep[i] = cell_ix[tri[i, 1]] in cells
tri_tmp = tri[i, 1]
keep_this = true
if has_cell_filter
keep_this = keep_this && cell_ix[tri_tmp] in cells
end
if has_face_filter
keep_this = keep_this && face_ix[tri_tmp] in faces
end
if has_bface_filter
keep_this = keep_this && face_ix[tri_tmp] in boundaryfaces
end
keep[i] = keep_this
end
tri = tri[keep, :]
tri, pts = remove_unused_points(tri, pts)
Expand Down Expand Up @@ -54,7 +89,13 @@ function Jutul.plot_cell_data_impl(m, data;
z_is_depth = Jutul.mesh_z_is_depth(m),
kwarg...
)
fig, ax = basic_3d_figure(resolution, z_is_depth = z_is_depth)
if dim(m) == 3
makefig = basic_3d_figure
else
makefig = basic_2d_figure
end
fig, ax = makefig(resolution, z_is_depth = z_is_depth)

p = Jutul.plot_cell_data!(ax, m, data; kwarg...)
min_data = minimum(data)
max_data = maximum(data)
Expand Down Expand Up @@ -114,7 +155,7 @@ function Jutul.plot_mesh_edges_impl!(ax, m;
transparency = true,
color = :black,
cells = nothing,
outer = true,
outer = dim(m) == 3,
linewidth = 0.3,
kwarg...)
m = physical_representation(m)
Expand Down
4 changes: 4 additions & 0 deletions src/Jutul.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ module Jutul
# Meat and potatoes
include("variable_evaluation.jl")
include("conservation/flux.jl")
include("conservation/fvm_assembly.jl")
include("linsolve/linsolve.jl")

include("context.jl")
Expand Down Expand Up @@ -100,4 +101,7 @@ module Jutul
# Support for SI unit conversion
include("units/units.jl")

# Nonlinear finite-volume discretizations
include("NFVM/NFVM.jl")

end # module
11 changes: 11 additions & 0 deletions src/NFVM/NFVM.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module NFVM
using Jutul
using LinearAlgebra
using StaticArrays
include("types.jl")
include("triplets.jl")
include("hap.jl")
include("decomposition.jl")
include("evaluation.jl")

end # module NFVM
220 changes: 220 additions & 0 deletions src/NFVM/decomposition.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
function get_half_face_normal(G, cell, face, normals, areas)
if G.faces.neighbors[face][2] == cell
sgn = -1
else
sgn = 1
end
return sgn*normals[face]*areas[face]
end

function ntpfa_decompose_half_face(G::UnstructuredMesh{D}, cell, face, K, cell_centroids, face_centroids, normals, areas, bnd_face_centroids, bnd_normals, bnd_areas) where D
# Vector we are going to decompose
normal = get_half_face_normal(G, cell, face, normals, areas)
AKn = K[cell]*normal
# Get local set of HAPs + weights
cells = Int[]
weights = Tuple{Float64, Float64}[]
points = SVector{D, Float64}[]
K_self = K[cell]
x_self = cell_centroids[cell]
for f in G.faces.cells_to_faces[cell]
l, r = G.faces.neighbors[f]
# Don't use left and right, use cell and other.
if l == cell
other = r
sgn = 1.0
else
other = l
sgn = -1.0
end
x_f = face_centroids[f]
n_f = sgn*normals[f]
K_other = K[other]
x_other = cell_centroids[other]
hp, w = find_harmonic_average_point(K_self, x_self, K_other, x_other, x_f, n_f)
# @info "Harmonic point found" hp w
push!(cells, other)
push!(points, hp)
push!(weights, w)
end
for bf in G.boundary_faces.cells_to_faces[cell]
# TODO: Something a bit smarter here.
push!(cells, cell)
push!(points, bnd_face_centroids[bf])
push!(weights, (0.5, 0.5))
end
# Next, figure out which ones we are going to keep.
x_t = cell_centroids[cell]

trip, trip_w = find_minimizing_basis(x_t, AKn, points, throw = false)
if any(isequal(0), trip)
out = nothing
else
l_r = NFVM.reconstruct_l(trip, trip_w, x_t, points)
# @assert norm(l_r - AKn)/norm(AKn) < 1e-8 "Mismatch in reconstruction, $l_r != $AKn"

active_weights = map(x -> weights[x], trip)
out = (
self = cell,
self_weights = map(first, active_weights), # Weights for self
other_cells_weights = map(last, active_weights), # Weights for other cells
other_cells = map(x -> cells[x], trip), # Other cell for each HAP
harmonic_average_points = map(x -> points[x], trip),
triplet_weights = trip_w,
Kn = AKn
)
end
return out
end

function remainder_trans(decomp, l, r, sgn = 1)
out = Tuple{Int, Float64}[]
for (i, c) in enumerate(decomp.other_cells)
if c != l && c != r
tw_i = decomp.triplet_weights[i]
cw_i = decomp.other_cells_weights[i]
w_i = sgn*tw_i*cw_i
push!(out, (c, w_i))
end
end
return out
end

function two_point_trans(decomp, cell)
# @warn "Decomposing $cell"
for (k, v) in pairs(decomp)
# @info "$k" v
end
T = 0.0
if decomp.self == cell
T += sum(decomp.self_weights.*decomp.triplet_weights)
end
for (i, c) in enumerate(decomp.other_cells)
if c == cell
tw_i = decomp.triplet_weights[i]
cw_i = decomp.other_cells_weights[i]
# @info "Found self in other $cell" c i tw_i cw_i
T += tw_i*cw_i
end
end
# @info "Final T = $T"
return T
end

function NFVMLinearDiscretization(t_tpfa::Real; left, right)
# Fallback constructor - essentially just a two-point flux with extra steps.
t_r = t_tpfa
t_l = -t_tpfa
t_mpfa = Tuple{Int, Float64}[]
return NFVMLinearDiscretization(left, right, t_l, t_r, t_mpfa)
end

function NFVMLinearDiscretization(decomp; left, right)
t_l = two_point_trans(decomp, left)
t_r = two_point_trans(decomp, right)

w_tot = -sum(decomp.triplet_weights)
if decomp.self == left
sgn = 1
t_l += w_tot
else
sgn = -1
t_r += w_tot
end
t_mpfa = remainder_trans(decomp, left, right, sgn)
t_l *= sgn
t_r *= sgn

return NFVMLinearDiscretization(left, right, t_l, t_r, t_mpfa)
end

function Jutul.subdiscretization(d::NFVMLinearDiscretization, subg, mapper::Jutul.FiniteVolumeGlobalMap, face)
(; left, right, T_left, T_right) = d
t_mpfa = d.mpfa
gmap = mapper.global_to_local

t_mpfa_new = Tuple{Int, Float64}[]
for tm in t_mpfa
# TODO: This is a bit dangerous - may have missing MPFA connections
c, trans = tm
try
new_c = Jutul.local_cell(c, mapper)
push!(t_mpfa_new, (new_c, trans))
catch
continue
end
end
l_new = Jutul.local_cell(left, mapper)
r_new = Jutul.local_cell(right, mapper)
return NFVMLinearDiscretization(
l_new,
r_new,
T_left,
T_right,
t_mpfa_new
)
end

function ntpfa_decompose_faces(G::UnstructuredMesh{D}, perm, scheme::Symbol = :avgmpfa;
faces = 1:number_of_faces(G),
tpfa_trans = missing,
extra_out = false
) where D
geo = tpfv_geometry(G)
areas = geo.areas
Vec_t = SVector{D, Float64}
possible_schemes = (:mpfa, :avgmpfa, :ntpfa, :nmpfa, :test_tpfa)
scheme in possible_schemes || throw(ArgumentError("Scheme must be one of $possible_schemes, was :$scheme"))

normals = reinterpret(Vec_t, geo.normals)
cell_centroids = reinterpret(Vec_t, geo.cell_centroids)
face_centroids = reinterpret(Vec_t, geo.face_centroids)

bnd_normals = reinterpret(Vec_t, geo.boundary_normals)
bnd_areas = geo.boundary_areas
bnd_face_centroids = reinterpret(Vec_t, geo.boundary_centroids)

if perm isa AbstractMatrix
K = SMatrix{D, D, Float64, D*D}[]
for i in axes(perm, 2)
push!(K, Jutul.expand_perm(perm[:, i], Val(D)))
end
else
perm::AbstractVector
K = perm
end

nf = number_of_faces(G)
function ntpfa_trans_for_face(f)
@assert f <= nf && f > 0 "Face $f not in range 1:$nf"
l, r = G.faces.neighbors[f]
left_decompose = ntpfa_decompose_half_face(G, l, f, K, cell_centroids, face_centroids, normals, areas, bnd_face_centroids, bnd_normals, bnd_areas)
right_decompose = ntpfa_decompose_half_face(G, r, f, K, cell_centroids, face_centroids, normals, areas, bnd_face_centroids, bnd_normals, bnd_areas)
if isnothing(left_decompose) || isnothing(right_decompose) || scheme == :test_tpfa
# A branch for handling fallback to TPFA scheme if something has
# gone wrong in the decomposition.
if ismissing(tpfa_trans)
error("Unable to use fallback transmissibility if tpfa_trans keyword argument is defaulted.")
end
T_fallback = tpfa_trans[f]
l_trans = NFVMLinearDiscretization(T_fallback, left = l, right = r)
r_trans = NFVMLinearDiscretization(T_fallback, left = l, right = r)
else
l_trans = NFVMLinearDiscretization(left_decompose, left = l, right = r)
r_trans = NFVMLinearDiscretization(right_decompose, left = l, right = r)
end
if scheme == :avgmpfa || scheme == :mpfa || scheme == :test_tpfa
disc = merge_to_avgmpfa(l_trans, r_trans)
else
disc = NFVMNonLinearDiscretization(l_trans, r_trans, scheme)
end
if extra_out
out = (disc, left_decompose, right_decompose)
else
out = disc
end
return out
end
disc = map(ntpfa_trans_for_face, faces)
return disc
end
Loading
Loading