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

Allow evaluating FE functions at arbitrary points #523

Merged
merged 68 commits into from
Jun 2, 2021
Merged
Show file tree
Hide file tree
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 Jan 26, 2021
f123693
Add function to evaluate FE functions
eschnett Jan 26, 2021
7e785be
New function inverse_map
ericneiva Jan 4, 2021
027fa14
bugfixed in CellField change_domain
ericneiva Jan 19, 2021
81bf213
Move code to the right location
eschnett Jan 26, 2021
0fd60ff
Reformat code
eschnett Jan 26, 2021
a7350a4
Merge branch 'master' into eschnett/evaluate
eschnett Jan 26, 2021
b6a18d4
Import return_cache
eschnett Jan 26, 2021
06b3524
Remove dependency on Bernstein.jl
eschnett Jan 27, 2021
c363d2d
Change sign convention for distance from simplex
eschnett Jan 27, 2021
0fcba26
Merge branch 'master' into eschnett/evaluate
eschnett Jan 27, 2021
489a377
Simplify finding minimum distance from simplices
eschnett Jan 27, 2021
01ef2f1
Calculate k-d tree only when needed
eschnett Jan 27, 2021
5103e07
simplexify: return tet simplex instead of hex simplex in 1d
eschnett Jan 28, 2021
bc6d049
Move evaluation function to MultiFields module
eschnett Jan 28, 2021
d1548f1
Comment code
eschnett Jan 28, 2021
c658948
Merge branch 'master' into eschnett/evaluate
eschnett Jan 31, 2021
921ced8
Merge branch 'master' into eschnett/evaluate
eschnett Feb 2, 2021
e7b2ddc
Merge branch 'master' into eschnett/evaluate
eschnett Feb 3, 2021
1e92b75
Merge branch 'master' into eschnett/evaluate
eschnett Feb 5, 2021
4f33d9b
Merge branch 'master' into eschnett/evaluate
eschnett Feb 28, 2021
9bd3a22
Add various comments with ideas or questions
eschnett Feb 28, 2021
c6ebff7
Add progress output while running test case
eschnett Feb 28, 2021
af56037
Shorten code
eschnett Feb 28, 2021
6b081cf
Rewrite code, making use of existing Gridap features
eschnett Mar 4, 2021
7c6038d
Merge branch 'master' into eschnett/evaluate
eschnett Mar 4, 2021
d6187d1
Commit current state
eschnett Mar 4, 2021
b2f4775
Merge branch 'master' into eschnett/evaluate
eschnett Mar 5, 2021
d5f15e6
Merge branch 'affine_map' into eschnett/evaluate
eschnett Mar 5, 2021
7544e8c
Things seem to work now.
eschnett Mar 5, 2021
0d765f1
Remove left-over comments
eschnett Mar 5, 2021
06ec403
Correct error bounds in self check
eschnett Mar 5, 2021
73672a3
Avoid temporary array
eschnett Mar 5, 2021
43afc11
Allow more general cell index types
eschnett Mar 5, 2021
f8998e3
Correct indentation
eschnett Mar 5, 2021
2f2e82f
Use vertex coordinates, not node coordinates to locate cells
eschnett Mar 6, 2021
aab614f
Merge branch 'master' into eschnett/evaluate
eschnett Mar 9, 2021
d02b072
Merge branch 'master' into eschnett/evaluate
eschnett Mar 9, 2021
3a393cd
Merge branch 'master' into eschnett/evaluate
eschnett Mar 25, 2021
db06d38
Merge branch 'master' into eschnett/evaluate
eschnett Mar 29, 2021
2c7bacd
Merge branch 'master' into eschnett/evaluate
eschnett Apr 9, 2021
7fccd3c
Merge branch 'master' into eschnett/evaluate
eschnett Apr 15, 2021
8d11d5c
Commit all changes
eschnett Apr 26, 2021
28a8563
Merge branch 'master' into eschnett/evaluate
eschnett Apr 26, 2021
6873673
Add tests for inverse maps
eschnett Apr 28, 2021
c1628dc
Merge branch 'master' into eschnett/evaluate
eschnett Apr 29, 2021
7197cec
Correct module imports
eschnett Apr 29, 2021
785876a
Make evaluate! for CellField more efficient
eschnett Apr 30, 2021
b65f9f6
Test evaluating cell fields on arrays of points
eschnett Apr 30, 2021
57ac76a
Remove duplicate include statement
eschnett Apr 30, 2021
4fef3f1
Implement efficient vectorized evaluation
eschnett Apr 30, 2021
a2fd337
Merge branch 'master' of github.com:gridap/Gridap.jl into HEAD
Balaje May 29, 2021
7548314
Move code to src/CellData from src/MultiField
Balaje May 31, 2021
5823b9a
Fixing comment in CellFields and remove repeating InverseFields Tests
Balaje May 31, 2021
a818db8
Merge pull request #1 from Balaje/eschnett/evaluate
eschnett Jun 1, 2021
0f6663f
Add more tests for evaluate
Balaje Jun 1, 2021
008a46a
Remove unused deps in MultiField.jl, more test for evaluate
Balaje Jun 1, 2021
e034de1
Fix an error
Balaje Jun 1, 2021
54962d9
Fix error in MultiField.jl
Balaje Jun 1, 2021
5c445d1
Remove comment
Balaje Jun 1, 2021
8ade674
Change to not export distance
Balaje Jun 1, 2021
0b4d2d9
Remove unused argument from point_to_cell
Balaje Jun 1, 2021
7a79a6e
Add interface for AbstractVector{<:Point}
Balaje Jun 2, 2021
620ee7f
Fix function names
Balaje Jun 2, 2021
0af55ff
Change from CellPoint to compute_cell_points_from_vector_of_points
Balaje Jun 2, 2021
4ff072c
Merge branch 'master' of github.com:gridap/Gridap.jl into tmp
Balaje Jun 2, 2021
b7f83ba
Update NEWS.md
Balaje Jun 2, 2021
6ce661f
Merge pull request #2 from Balaje/eschnett/evaluate
eschnett Jun 2, 2021
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
12 changes: 7 additions & 5 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Experimental support for mixed dimensional PDEs. Since PR [#567](https://github.com/gridap/Gridap.jl/pull/567).
- Added `get_cell_dof_basis(model,cell_reffes,::Conformity)` and `get_cell_shapefuns(model,cell_reffes,::Conformity)`. Since PR [#579](https://github.com/gridap/Gridap.jl/pull/579).
- Implemented `get_cell_dof_basis` and `get_cell_shapefuns` for global RT FE spaces in a new file `DivConformingFESpaces.jl`. Since PR [#579](https://github.com/gridap/Gridap.jl/pull/579).
- Added support to allow evaluation of FE functions at arbitrary points. Since PR [#523](https://github.com/gridap/Gridap.jl/pull/523).
- Implemented `compute_cell_points_from_vector_of_points` to build `CellPoint` from a vector of points. Since PR [#523](https://github.com/gridap/Gridap.jl/pull/523).

### Changed
- Major refactoring in the handling of blocks (e.g. in multi-field and skeleton terms). The new code follows a much more simple approach based in the new type `ArrayBlock`. Since PR [#583](https://github.com/gridap/Gridap.jl/pull/583).
Expand All @@ -28,7 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- All code associated with with `BlockArrayCoo`. Since PR [#583](https://github.com/gridap/Gridap.jl/pull/583).
- Module `Gridap.Integration` has been deleted and its contents have been merged into `Gridap.ReferenceFEs` module.
- Types `SparseMatrixCSR` and `SymSparseMatrixCSR` have been moved to the registered package [`SparseMatricesCSR`](https://github.com/gridap/SparseMatricesCSR.jl). To use them simply add `SparseMatricesCSR` into your environment and type `using SparseMatricesCSR`. Since Since PR [#568](https://github.com/gridap/Gridap.jl/pull/568).
- Removed `PushForwardMap` and all code depending upon it. Since PR [#579](https://github.com/gridap/Gridap.jl/pull/579).
- Removed `PushForwardMap` and all code depending upon it. Since PR [#579](https://github.com/gridap/Gridap.jl/pull/579).

## [0.15.5] - 2021-05-25

Expand All @@ -43,7 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [0.15.3] - 2021-03-16

### Added
### Added
- `get_cell_map` now returns array of `AffineMap` for linear grids of simplices. Needed to compute Laplacian operator, inverse maps etc. Since PR [#553](https://github.com/gridap/Gridap.jl/pull/553).

### Fixed
Expand Down Expand Up @@ -83,7 +85,7 @@ This version is a major (backwards-incompatible) refactoring of the project whic
- Bug-fix for 32-bit Julia: Replace all occurences of Int64 by Int. Since PR [#445](https://github.com/gridap/Gridap.jl/pull/445).
- Bug-fix for 32-bit Julia. Using inttype=Int keyword argument for JSON parsing. Since PR [#456](https://github.com/gridap/Gridap.jl/pull/456).

## [0.14.1] - 2020-09-17
## [0.14.1] - 2020-09-17

### Added
- Added VectorWithEntryInserted and VectorWithEntryRemoved. Since PR [#401](https://github.com/gridap/Gridap.jl/pull/401/).
Expand All @@ -102,7 +104,7 @@ This version is a major (backwards-incompatible) refactoring of the project whic
- First and second argument switch in `update_state_variables!` in order to have function-first style. Since PR [#376](https://github.com/gridap/Gridap.jl/pull/376/).
- Table struct has been generalized such that data and ptrs arrays can be of an arbitrary type extending AbstractArray. Since PR [#310](https://github.com/gridap/Gridap.jl/pull/310/)
- `interpolate, interpolate!, interpolate_dirichlet...` switched argument order to function first style. For instance `interpolate(u, V)` instead of `interpolate(V, u)`

### Added
- Allowing the construction of an `HomogeneousTrialFESpace` from a `TrialFESpace`. Since PR [#384](https://github.com/gridap/Gridap.jl/pull/384).
- Support for automatic differentiation of residuals and Jacobians in multi-field computations since PR [#383](https://github.com/gridap/Gridap.jl/pull/383/).
Expand All @@ -113,7 +115,7 @@ This version is a major (backwards-incompatible) refactoring of the project whic

## [0.13.4] - 2020-08-23

### Added
### Added
- New `FilteredCellArray` since PR [#372](https://github.com/gridap/Gridap.jl/pull/372/).

## [0.13.3] - 2020-08-12
Expand Down
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
NearestNeighbors = "b8a86587-4115-5ab1-83bc-aa920d37bbce"
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
Expand All @@ -40,6 +41,7 @@ JLD2 = "0.1.11, 0.3, 0.4"
JSON = "0.21.0"
LineSearches = "7.0.1"
NLsolve = "4.3.0"
NearestNeighbors = "0.4.8"
QuadGK = "2.3.1, 2.4"
SparseMatricesCSR = "0.6"
StaticArrays = "0.12.1, 1.0"
Expand Down
10 changes: 9 additions & 1 deletion src/CellData/CellData.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,20 @@ using DocStringExtensions
using FillArrays

using Gridap.Helpers
using Gridap.Arrays
using Gridap.Algebra
using Gridap.Arrays
using Gridap.TensorValues
using Gridap.Fields
using Gridap.ReferenceFEs
using Gridap.Geometry

using NearestNeighbors
using StaticArrays

import Gridap.Arrays: lazy_append
import Gridap.Arrays: get_array
import Gridap.Arrays: evaluate!
import Gridap.Arrays: return_cache
import Gridap.Fields: gradient
import Gridap.Fields: ∇∇
import Gridap.Fields: integrate
Expand Down Expand Up @@ -57,6 +61,10 @@ export CellDof
export get_normal_vector
export get_cell_measure

export make_inverse_table
export point_to_cell!
Copy link
Member

@fverdugo fverdugo Jun 2, 2021

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:

  1. Do not export point_to_cell! and rename it to _point_to_cell! so that it is clear that it's private.
  2. Make public also the mechanism to generate the cache. In this case, follow the API of the abstract type Map just to be consistent with other parts of the code.
struct PointToCellMap{T<:Triangulation} <: Map
  trian::T
end

return_cache(k::PointToCellMap,x::Point) = ...
evaluate!(cache,k::PointToCellMap,x::Point) = ...

export compute_cell_points_from_vector_of_points

export DomainContribution
export num_domains
export get_domains
Expand Down
185 changes: 173 additions & 12 deletions src/CellData/CellFields.jl
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.
Expand Down Expand Up @@ -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

Copy link
Member

Choose a reason for hiding this comment

The 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)
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/MultiField/MultiField.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ using Gridap.TensorValues
using Gridap.CellData
using Gridap.Fields

using Gridap.FESpaces: FEBasis, TestBasis, TrialBasis, get_cell_dof_values
fverdugo marked this conversation as resolved.
Show resolved Hide resolved
using Gridap.FESpaces: SingleFieldFEBasis, TestBasis, TrialBasis

using FillArrays
using SparseArrays
using LinearAlgebra
import BlockArrays
using BlockArrays

export num_fields
export compute_field_offsets
Expand Down
1 change: 0 additions & 1 deletion src/MultiField/MultiFieldCellFields.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

struct MultiFieldCellField{DS<:DomainStyle} <: CellField
single_fields::Vector{<:CellField}
trian::Triangulation
Expand Down
Loading