-
Notifications
You must be signed in to change notification settings - Fork 97
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
Allow evaluating FE functions at arbitrary points #523
Merged
Merged
Changes from all commits
Commits
Show all changes
68 commits
Select commit
Hold shift + click to select a range
6064415
Allow evaluating FE functions at arbitrary points
eschnett f123693
Add function to evaluate FE functions
eschnett 7e785be
New function inverse_map
ericneiva 027fa14
bugfixed in CellField change_domain
ericneiva 81bf213
Move code to the right location
eschnett 0fd60ff
Reformat code
eschnett a7350a4
Merge branch 'master' into eschnett/evaluate
eschnett b6a18d4
Import return_cache
eschnett 06b3524
Remove dependency on Bernstein.jl
eschnett c363d2d
Change sign convention for distance from simplex
eschnett 0fcba26
Merge branch 'master' into eschnett/evaluate
eschnett 489a377
Simplify finding minimum distance from simplices
eschnett 01ef2f1
Calculate k-d tree only when needed
eschnett 5103e07
simplexify: return tet simplex instead of hex simplex in 1d
eschnett bc6d049
Move evaluation function to MultiFields module
eschnett d1548f1
Comment code
eschnett c658948
Merge branch 'master' into eschnett/evaluate
eschnett 921ced8
Merge branch 'master' into eschnett/evaluate
eschnett e7b2ddc
Merge branch 'master' into eschnett/evaluate
eschnett 1e92b75
Merge branch 'master' into eschnett/evaluate
eschnett 4f33d9b
Merge branch 'master' into eschnett/evaluate
eschnett 9bd3a22
Add various comments with ideas or questions
eschnett c6ebff7
Add progress output while running test case
eschnett af56037
Shorten code
eschnett 6b081cf
Rewrite code, making use of existing Gridap features
eschnett 7c6038d
Merge branch 'master' into eschnett/evaluate
eschnett d6187d1
Commit current state
eschnett b2f4775
Merge branch 'master' into eschnett/evaluate
eschnett d5f15e6
Merge branch 'affine_map' into eschnett/evaluate
eschnett 7544e8c
Things seem to work now.
eschnett 0d765f1
Remove left-over comments
eschnett 06ec403
Correct error bounds in self check
eschnett 73672a3
Avoid temporary array
eschnett 43afc11
Allow more general cell index types
eschnett f8998e3
Correct indentation
eschnett 2f2e82f
Use vertex coordinates, not node coordinates to locate cells
eschnett aab614f
Merge branch 'master' into eschnett/evaluate
eschnett d02b072
Merge branch 'master' into eschnett/evaluate
eschnett 3a393cd
Merge branch 'master' into eschnett/evaluate
eschnett db06d38
Merge branch 'master' into eschnett/evaluate
eschnett 2c7bacd
Merge branch 'master' into eschnett/evaluate
eschnett 7fccd3c
Merge branch 'master' into eschnett/evaluate
eschnett 8d11d5c
Commit all changes
eschnett 28a8563
Merge branch 'master' into eschnett/evaluate
eschnett 6873673
Add tests for inverse maps
eschnett c1628dc
Merge branch 'master' into eschnett/evaluate
eschnett 7197cec
Correct module imports
eschnett 785876a
Make evaluate! for CellField more efficient
eschnett b65f9f6
Test evaluating cell fields on arrays of points
eschnett 57ac76a
Remove duplicate include statement
eschnett 4fef3f1
Implement efficient vectorized evaluation
eschnett a2fd337
Merge branch 'master' of github.com:gridap/Gridap.jl into HEAD
Balaje 7548314
Move code to src/CellData from src/MultiField
Balaje 5823b9a
Fixing comment in CellFields and remove repeating InverseFields Tests
Balaje a818db8
Merge pull request #1 from Balaje/eschnett/evaluate
eschnett 0f6663f
Add more tests for evaluate
Balaje 008a46a
Remove unused deps in MultiField.jl, more test for evaluate
Balaje e034de1
Fix an error
Balaje 54962d9
Fix error in MultiField.jl
Balaje 5c445d1
Remove comment
Balaje 8ade674
Change to not export distance
Balaje 0b4d2d9
Remove unused argument from point_to_cell
Balaje 7a79a6e
Add interface for AbstractVector{<:Point}
Balaje 620ee7f
Fix function names
Balaje 0af55ff
Change from CellPoint to compute_cell_points_from_vector_of_points
Balaje 4ff072c
Merge branch 'master' of github.com:gridap/Gridap.jl into tmp
Balaje b7f83ba
Update NEWS.md
Balaje 6ce661f
Merge pull request #2 from Balaje/eschnett/evaluate
eschnett File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
|
||
""" | ||
A single point or an array of points on the cells of a Triangulation | ||
CellField objects can be evaluated efficiently at CellPoint instances. | ||
|
@@ -208,20 +207,182 @@ get_data(f::GenericCellField) = f.cell_field | |
get_triangulation(f::GenericCellField) = f.trian | ||
DomainStyle(::Type{GenericCellField{DS}}) where DS = DS() | ||
|
||
# Evaluation of CellFields | ||
|
||
(a::CellField)(x) = evaluate(a,x) | ||
""" | ||
dist = distance(polytope::ExtrusionPolytope, | ||
inv_cmap::Field, | ||
x::Point) | ||
|
||
Calculate distance from point `x` to the polytope. The polytope is | ||
given by its type and by the inverse cell map, i.e. by the map from | ||
the physical to the reference space. | ||
|
||
Positive distances are outside the polytope, negative distances are | ||
inside the polytope. | ||
|
||
The distance is measured in an unspecified norm, currently the L∞ | ||
norm. | ||
""" | ||
function distance(polytope::ExtrusionPolytope, inv_cmap::Field, x::Point) | ||
extrusion = polytope.extrusion | ||
isempty(extrusion) && return zero(eltype(x)) | ||
p = inv_cmap(x) | ||
if all(e == HEX_AXIS for e in extrusion) | ||
# Boundaries are at `a=0` and `a=1` in each direction | ||
return maximum(max(0 - a, a - 1) for a in p) | ||
elseif all(e == TET_AXIS for e in extrusion) | ||
# Calculate barycentric coordinates | ||
λ = Point(p..., 1 - sum(p)) | ||
return maximum(-λ) | ||
else | ||
@notimplemented "Only hypercubes and simplices are implemented so far" | ||
end | ||
end | ||
|
||
function return_cache(f::CellField,x::Point) | ||
trian = get_triangulation(f) | ||
cache1 = _point_to_cell_cache(trian) | ||
|
||
cell_f = get_array(f) | ||
cell_f_cache = array_cache(cell_f) | ||
cf = testitem(cell_f) | ||
f_cache = return_cache(cf,x) | ||
cache2 = cell_f_cache, f_cache, cell_f, f | ||
|
||
return cache1,cache2 | ||
end | ||
|
||
function _point_to_cell_cache(trian::Triangulation) | ||
topo = GridTopology(trian) | ||
vertex_coordinates = Geometry.get_vertex_coordinates(topo) | ||
kdtree = KDTree(map(nc -> SVector(Tuple(nc)), vertex_coordinates)) | ||
D = num_cell_dims(trian) | ||
vertex_to_cells = get_faces(topo, 0, D) | ||
cell_to_ctype = get_cell_type(trian) | ||
ctype_to_reffe = get_reffes(trian) | ||
ctype_to_polytope = map(get_polytope, ctype_to_reffe) | ||
cell_map = get_cell_map(trian) | ||
cache1 = kdtree, vertex_to_cells, cell_to_ctype, ctype_to_polytope, cell_map | ||
end | ||
|
||
function point_to_cell!(cache, x::Point) | ||
kdtree, vertex_to_cells, cell_to_ctype, ctype_to_polytope, cell_map = cache | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could probably encapsulate this code in a function and do dispatching with respect to the triangulation type. The code below is for an unstructured (simplicial) mesh. We could also consider the case for a structured Cartesian mesh (which is much easier, no tree involved). |
||
# Find nearest vertex | ||
id,dist = nn(kdtree, SVector(Tuple(x))) | ||
|
||
# Find all neighbouring cells | ||
cells = vertex_to_cells[id] | ||
@assert !isempty(cells) | ||
|
||
# Calculate the distance from the point to all the cells. Without | ||
# round-off, and with non-overlapping cells, the distance would be | ||
# negative for exactly one cell and positive for all other ones. Due | ||
# to round-off, the distance can be slightly negative or slightly | ||
# positive for points near cell boundaries, in particular near | ||
# vertices. In this case, choose the cell with the smallest | ||
# distance, and check that the distance (if positive) is at most at | ||
# round-off level. | ||
T = eltype(dist) | ||
function cell_distance(cell::Integer) | ||
ctype = cell_to_ctype[cell] | ||
polytope = ctype_to_polytope[ctype] | ||
cmap = cell_map[cell] | ||
inv_cmap = inverse_map(cmap) | ||
return distance(polytope, inv_cmap, x) | ||
end | ||
# findmin, without allocating an array | ||
cell = zero(eltype(cells)) | ||
dist = T(Inf) | ||
for jcell in cells | ||
jdist = cell_distance(jcell) | ||
if jdist < dist | ||
cell = jcell | ||
dist = jdist | ||
end | ||
end | ||
# Ensure the point is inside one of the cells, up to round-off errors | ||
@check dist ≤ 1000eps(T) "Point is not inside any cell" | ||
|
||
return cell | ||
end | ||
|
||
function evaluate!(cache,f::CellField,x::Point) | ||
@notimplemented """\n | ||
Evaluation of a CellField at a given Point is not implemented yet. | ||
cache1,cache2 = cache | ||
cell_f_cache, f_cache, cell_f, f₀ = cache2 | ||
@check f === f₀ "Wrong cache" | ||
|
||
cell = point_to_cell!(cache1, x) | ||
cf = getindex!(cell_f_cache, cell_f, cell) | ||
fx = evaluate!(f_cache, cf, x) | ||
return fx | ||
end | ||
|
||
eschnett marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return_cache(f::CellField,xs::AbstractVector{<:Point}) = return_cache(f,testitem(xs)) | ||
|
||
# # Simple version: | ||
# function evaluate!(cache,f::CellField,xs::AbstractVector{<:Point}) | ||
# return map(x->evaluate!(cache,f,x), xs) | ||
# end | ||
|
||
function make_inverse_table(i2j::AbstractVector{<:Integer},nj::Int) | ||
ni = length(i2j) | ||
@assert nj≥0 | ||
|
||
p = sortperm(i2j) | ||
# i2j[p] is a sorted array of js | ||
|
||
data = p | ||
ptrs = Array{Int}(undef, nj+1) | ||
i2lis = Array{Int}(undef, ni) | ||
jprev = zero(eltype(i2j)) | ||
liprev = 0 | ||
for (n,i) in enumerate(p) | ||
j = i2j[i] | ||
@assert jprev≤j≤nj | ||
li = (j==jprev ? liprev : 0) + 1 | ||
ptrs[jprev+1:j] .= n | ||
i2lis[i] = li | ||
jprev = j | ||
liprev = li | ||
end | ||
ptrs[jprev+1:nj+1] .= ni+1 | ||
j2is = Table(data,ptrs) | ||
|
||
This is a feature that we want to have at some point in Gridap. | ||
If you are ready to help with this implementation, please contact the | ||
Gridap administrators. | ||
""" | ||
return j2is,i2lis | ||
end | ||
|
||
# Efficient version: | ||
function evaluate!(cache,f::CellField,point_to_x::AbstractVector{<:Point}) | ||
cache1,cache2 = cache | ||
kdtree, vertex_to_cells, cell_to_ctype, ctype_to_polytope, cell_map = cache1 | ||
cell_f_cache, f_cache, cell_f, f₀ = cache2 | ||
@check f === f₀ "Wrong cache" | ||
|
||
ncells = length(cell_map) | ||
x_to_cell(x) = point_to_cell!(cache1,x) | ||
point_to_cell = map(x_to_cell,point_to_x) | ||
cell_to_points,point_to_lpoint = make_inverse_table(point_to_cell,ncells) | ||
cell_to_xs = lazy_map(Broadcasting(Reindex(point_to_x)),cell_to_points) | ||
cell_to_f = get_array(f) | ||
cell_to_fxs = lazy_map(evaluate,cell_to_f,cell_to_xs) | ||
point_to_fxs = lazy_map(Reindex(cell_to_fxs),point_to_cell) | ||
point_to_fx = lazy_map(getindex,point_to_fxs,point_to_lpoint) | ||
collect(point_to_fx) # Collect into a plain array | ||
end | ||
|
||
function compute_cell_points_from_vector_of_points(xs::AbstractVector{<:Point}, trian::Triangulation, domain_style::PhysicalDomain) | ||
cache1 = _point_to_cell_cache(trian) | ||
x_to_cell(x) = point_to_cell!(cache1, x) | ||
point_to_cell = map(x_to_cell, xs) | ||
ncells = num_cells(trian) | ||
cell_to_points, point_to_lpoint = make_inverse_table(point_to_cell, ncells) | ||
cell_to_xs = lazy_map(Broadcasting(Reindex(xs)), cell_to_points) | ||
cell_point_xs = CellPoint(cell_to_xs, trian, PhysicalDomain()) | ||
end | ||
|
||
(a::CellField)(x) = evaluate(a,x) | ||
|
||
function evaluate!(cache,f::CellField,x::CellPoint) | ||
_f, _x = _to_common_domain(f,x) | ||
cell_field = get_data(_f) | ||
|
@@ -334,11 +495,11 @@ struct OperationCellField{DS} <: CellField | |
r = Fields.BroadcastingFieldOpMap(op.op)(axi...) | ||
catch | ||
@unreachable """\n | ||
It is not possible to perform operation $(op.op) on the given cell fields. | ||
It is not possible to perform the operation "$(op.op)" on the given cell fields. | ||
|
||
See the caught error for more information. (If you are using Visual | ||
See the caught error for more information. (If you are using the Visual | ||
Studio Code REPL you might not see the caught error, please use the | ||
command-line REPL). | ||
command-line REPL instead). | ||
""" | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are exporting
point_to_cell!
but the function to generate its cache object seems to be private.Here, there are 2 options:
point_to_cell!
and rename it to_point_to_cell!
so that it is clear that it's private.Map
just to be consistent with other parts of the code.