Skip to content

Commit 0951a20

Browse files
authored
Merge pull request #114 from sintefmath/dev
Faster and more robust trajectory search, adjoint fix for multimodel, improved Gmsh support, litre fix and other minor improvements
2 parents 430c986 + 8792fd3 commit 0951a20

File tree

14 files changed

+292
-40
lines changed

14 files changed

+292
-40
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "Jutul"
22
uuid = "2b460a1a-8a2b-45b2-b125-b5c536396eb9"
33
authors = ["Olav Møyner <[email protected]>"]
4-
version = "0.3.3"
4+
version = "0.3.4"
55

66
[deps]
77
AlgebraicMultigrid = "2169fc97-5a83-5252-b627-83903c6c433c"

ext/JutulGmshExt/interface.jl

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,44 @@
11

2-
function Jutul.mesh_from_gmsh(pth; verbose = false, kwarg...)
3-
Gmsh.initialize()
2+
function Jutul.mesh_from_gmsh(pth; manage_gmsh = true, kwarg...)
3+
if manage_gmsh
4+
Gmsh.initialize()
5+
end
46
ext = pth |> splitext |> last
57
gmsh.open(pth)
68
if lowercase(ext) == ".geo"
79
gmsh.model.mesh.generate()
810
end
11+
g = missing
12+
try
13+
g = Jutul.mesh_from_gmsh(; kwarg...)
14+
finally
15+
if manage_gmsh
16+
Gmsh.finalize()
17+
end
18+
end
19+
if ismissing(g)
20+
error("Failed to parse mesh")
21+
end
22+
return g
23+
end
924

25+
function Jutul.mesh_from_gmsh(; verbose = false, reverse_z = false, kwarg...)
1026
dim = gmsh.model.getDimension()
1127
dim == 3 || error("Only 3D models are supported")
1228

1329
gmsh.model.mesh.removeDuplicateNodes()
30+
if reverse_z
31+
# Note: Gmsh API lets us send only the first 3 rows of the 4 by 4 matrix
32+
# which is sufficient here.
33+
gmsh.model.mesh.affineTransform(
34+
[
35+
1.0, 0.0, 0.0, 0.0,
36+
0.0, 1.0, 0.0, 0.0,
37+
0.0, 0.0, -1.0, 0.0
38+
]
39+
)
40+
gmsh.model.mesh.generate()
41+
end
1442
node_tags, pts, = gmsh.model.mesh.getNodes()
1543
node_remap = Dict{UInt64, Int}()
1644
for (i, tag) in enumerate(node_tags)
@@ -30,9 +58,6 @@ function Jutul.mesh_from_gmsh(pth; verbose = false, kwarg...)
3058
face_lookup = generate_face_lookup(faces_to_nodes)
3159

3260
cells_to_faces = parse_cells(remaps, faces_to_nodes, face_lookup, verbose = verbose)
33-
# We are done with Gmsh.jl at this point, finalize it.
34-
Gmsh.finalize()
35-
3661
neighbors = build_neighbors(cells_to_faces, faces_to_nodes, face_lookup)
3762

3863
# Make both of these in case we have rogue faces that are not connected to any cell.

src/ad/gradients.jl

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ function solve_adjoint_sensitivities(case::JutulCase, states::Vector, G; dt = ca
8585
)
8686
end
8787

88-
8988
function solve_adjoint_sensitivities(case::JutulCase, some_kind_of_result, G; kwarg...)
9089
if hasproperty(some_kind_of_result, :result)
9190
simresult = some_kind_of_result.result
@@ -317,6 +316,7 @@ function merge_sparsity!(sparsity::AbstractDict, s_new::AbstractDict)
317316
merge_sparsity!(sparsity[k], v)
318317
end
319318
end
319+
320320
function merge_sparsity!(sparsity::AbstractVector, s_new::AbstractVector)
321321
for k in s_new
322322
push!(sparsity, k)
@@ -355,7 +355,7 @@ function state_gradient_outer!(∂F∂x, F, model, state, extra_arg; sparsity =
355355
state_gradient_inner!(∂F∂x, F, model, state, nothing, extra_arg; sparsity = sparsity)
356356
end
357357

358-
function state_gradient_inner!(∂F∂x, F, model, state, tag, extra_arg, eval_model = model; sparsity = nothing)
358+
function state_gradient_inner!(∂F∂x, F, model, state, tag, extra_arg, eval_model = model; sparsity = nothing, symbol = nothing)
359359
layout = matrix_layout(model.context)
360360
get_partial(x::AbstractFloat, i) = 0.0
361361
get_partial(x::ForwardDiff.Dual, i) = x.partials[i]
@@ -376,8 +376,12 @@ function state_gradient_inner!(∂F∂x, F, model, state, tag, extra_arg, eval_m
376376
end
377377
end
378378

379-
function diff_entity!(∂F∂x, state, i, S, ne, np, offset)
380-
state_i = local_ad(state, i, S)
379+
function diff_entity!(∂F∂x, state, i, S, ne, np, offset, symbol)
380+
if !isnothing(symbol)
381+
state_i = local_ad(state, i, S, symbol)
382+
else
383+
state_i = local_ad(state, i, S)
384+
end
381385
v = F(eval_model, state_i, extra_arg...)
382386
store_partials!(∂F∂x, v, i, ne, np, offset)
383387
end
@@ -395,7 +399,7 @@ function state_gradient_inner!(∂F∂x, F, model, state, tag, extra_arg, eval_m
395399
ltag = get_entity_tag(tag, e)
396400
S = typeof(get_ad_entity_scalar(1.0, np, tag = ltag))
397401
for i in it_rng
398-
diff_entity!(∂F∂x, state, i, S, ne, np, offset)
402+
diff_entity!(∂F∂x, state, i, S, ne, np, offset, symbol)
399403
end
400404
end
401405
offset += ne*np
@@ -471,7 +475,7 @@ function next_lagrange_multiplier!(adjoint_storage, i, G, state, state0, state_n
471475
else
472476
dt_next = timesteps[i+1]
473477
forces_next = forces_for_timestep(backward_sim, all_forces, timesteps, i+1)
474-
@tic "jacobian (with state0)" adjoint_reassemble!(backward_sim, state_next, state, dt_next, forces_next, t + dt_next)
478+
@tic "jacobian (with state0)" adjoint_reassemble!(backward_sim, state_next, state, dt_next, forces_next, t + dt)
475479
lsys_next = backward_sim.storage.LinearizedSystem
476480
op = linear_operator(lsys_next, skip_red = true)
477481
# In-place version of
@@ -673,6 +677,9 @@ function evaluate_objective(G, model, states, timesteps, all_forces; large_value
673677
function convert_state_to_jutul_storage(model::MultiModel, x::AbstractDict)
674678
s = JutulStorage()
675679
for (k, v) in pairs(x)
680+
if k == :substates
681+
continue
682+
end
676683
s[k] = JutulStorage(v)
677684
end
678685
return s
@@ -869,9 +876,10 @@ function adjoint_transfer_canonical_order_inner!(λ, dx, model, ::BlockMajorLayo
869876
if bz > 0
870877
error("Assumed that block major has a single entity group")
871878
end
872-
bz = degrees_of_freedom_per_entity(model, e)
879+
bz = degrees_of_freedom_per_entity(model, e)::Int
873880
end
874881
n = length(dx) ÷ bz
882+
n::Int
875883
if to_canonical
876884
for b in 1:bz
877885
for i in 1:n

src/ad/local_ad.jl

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,20 @@ struct LocalPerspectiveAD{T, N, A<:AbstractArray{T,N}, I} <: AbstractArray{T,N}
66
end
77

88
function LocalPerspectiveAD(a::A, index::I_t) where {A<:AbstractArray, I_t<:Integer}
9-
LocalPerspectiveAD{eltype(a), ndims(A), A, I_t}(index, a)
9+
return LocalPerspectiveAD{eltype(a), ndims(A), A, I_t}(index, a)
1010
end
1111

1212
struct LocalStateAD{T, I, E} # Data type, index, entity tag
1313
index::I
1414
data::T
1515
end
1616

17+
struct MultiModelLocalStateAD{T, I, E} # Data type, index, entity tag
18+
symbol::Symbol
19+
index::I
20+
data::T
21+
end
22+
1723
Base.keys(x::LocalStateAD) = keys(getfield(x, :data))
1824

1925
struct ValueStateAD{T} # Data type
@@ -22,6 +28,12 @@ end
2228

2329
Base.keys(x::ValueStateAD) = keys(getfield(x, :data))
2430

31+
function convert_to_immutable_storage(x::ValueStateAD)
32+
data = getfield(x, :data)
33+
data = convert_to_immutable_storage(data)
34+
return ValueStateAD(data)
35+
end
36+
2537
const StateType = Union{NamedTuple,AbstractDict,JutulStorage}
2638

2739
as_value(x::StateType) = ValueStateAD(x)
@@ -31,7 +43,6 @@ export local_ad
3143
@inline local_ad(v, ::Nothing) = as_value(v)
3244
@inline local_ad(v, i) = v
3345

34-
3546
@inline function new_entity_index(state::LocalStateAD{T, I, E}, index::I) where {T, I, E}
3647
return LocalStateAD{T, I, E}(index, getfield(state, :data))
3748
end
@@ -40,7 +51,6 @@ end
4051
return x
4152
end
4253

43-
4454
@inline local_entity(a::LocalPerspectiveAD) = a.index
4555

4656
@inline function value_or_ad(A::LocalPerspectiveAD{T}, v::T, entity) where T
@@ -80,7 +90,6 @@ end
8090
end
8191
@inline Base.haskey(state::ValueStateAD, f::Symbol) = haskey(getfield(state, :data), f)
8292

83-
8493
# Match in type - pass index on
8594
@inline next_level_local_ad(x::AbstractArray{T}, ::Type{T}, index) where T = local_ad(x, index)
8695

@@ -140,10 +149,26 @@ end
140149
return next_level_local_ad(val, E, index)
141150
end
142151

152+
@inline function Base.getproperty(state::MultiModelLocalStateAD{T, I, E}, f::Symbol) where {T, I, E}
153+
index = getfield(state, :index)
154+
inner_state = getfield(state, :data)
155+
val = getproperty(inner_state, f)
156+
sym = getfield(state, :symbol)
157+
if sym == f
158+
return next_level_local_ad(val, E, index)
159+
else
160+
return as_value(val)
161+
end
162+
end
163+
143164
@inline function Base.getindex(state::LocalStateAD, s::Symbol)
144165
Base.getproperty(state, s)
145166
end
146167

168+
@inline function Base.getindex(state::MultiModelLocalStateAD, s::Symbol)
169+
Base.getproperty(state, s)
170+
end
171+
147172
@inline function Base.getproperty(state::ValueStateAD{T}, f::Symbol) where {T}
148173
inner_state = getfield(state, :data)
149174
val = getproperty(inner_state, f)
@@ -163,10 +188,18 @@ Create local_ad for state for index I of AD tag of type ad_tag
163188
local_state_ad(state, index, ad_tag)
164189
end
165190

191+
@inline function local_ad(state, index, ad_tag, symbol)
192+
local_state_ad(state, index, ad_tag, symbol)
193+
end
194+
166195
@inline function local_state_ad(state::T, index::I, ad_tag::∂T) where {T, I<:Integer, ∂T}
167196
return LocalStateAD{T, I, ad_tag}(index, state)
168197
end
169198

199+
@inline function local_state_ad(state::T, index::I, ad_tag::∂T, symbol::Symbol) where {T, I<:Integer, ∂T}
200+
return MultiModelLocalStateAD{T, I, ad_tag}(symbol, index, state)
201+
end
202+
170203
function Base.show(io::IO, t::MIME"text/plain", x::LocalStateAD{T, I, E}) where {T, I, E}
171204
print(io, "Local state for $(unpack_tag(E)) -> $(getfield(x, :index)) with fields $(keys(getfield(x, :data)))")
172205
end

src/core_types/core_types.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,10 @@ function convert_to_immutable_storage(S::JutulStorage)
523523
return JutulStorage(tup)
524524
end
525525

526+
function convert_to_immutable_storage(S::NamedTuple)
527+
return S
528+
end
529+
526530
function Base.getindex(S::JutulStorage, i::Int)
527531
d = data(S)
528532
if d isa OrderedDict

src/ext/gmsh_ext.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
export mesh_from_gmsh
22

33
"""
4-
G = mesh_from_gmsh(pth; verbose = false)
4+
G = mesh_from_gmsh(pth)
5+
G = mesh_from_gmsh()
6+
G = mesh_from_gmsh(pth; verbose = true)
57
68
Parse a Gmsh file and return a Jutul `UnstructuredMesh` (in 3D only). Requires
7-
the Gmsh.jl package to be loaded. Please note that Gmsh is GPL licensed unless
8-
you have obtained another type of license from the authors.
9+
the Gmsh.jl package to be loaded. If no path is provided in `pth` it is assumed
10+
that you are managing the Gmsh state manually and it will use the current
11+
selected mesh inside Gmsh. Please note that Gmsh is GPL licensed unless you have
12+
obtained another type of license from the authors.
913
"""
1014
function mesh_from_gmsh
1115

src/meshes/meshes.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,7 @@ function face_geometry_helper(G, D, nc, nf, e)
279279
end
280280
return (areas, normals, centroids)
281281
end
282+
283+
284+
import Base: promote_rule
285+
promote_rule(::Type{UnstructuredMesh}, ::Type{CartesianMesh}) = UnstructuredMesh

0 commit comments

Comments
 (0)