-
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
need a way to loop over quadrature points #907
Comments
(You could also have the analogous API corresponding to |
Hi @stevengj, It is possible to get the values of the bilinear and linear forms at quadrature points, but it requires some effort. Accessing the elemental matrices (once integrated) is much more easy. Is this perhaps enough for your needs? using Gridap
using Gridap.FESpaces
U = ... # trial space
V = ... # test space
Ω = ... # triangulation
dv = get_fe_basis(V)
du = get_trial_fe_basis(U)
cell = 100
a(du,dv)[Ω][cell] # elemental matrix of the cell number 100 in the triangulation Ω |
We need the individual quadrature points, not just the cell-integrated elemental matrices. (The reason is that backpropagating from assembly to an interpolation function from an external grid requires us to map each quadrature point to the external grid via the interpolation weights for that point, and these vary from point to point.) |
Note that I originally suggested a lower-level API, but then deleted it in favor of the simpler API above, but maybe it's clearer to give the lower-level API. In particular, we just need the same quadrature points and bilinear-form values that you use internally in quadratureloop(a, U, V) do aₓ, x, wₓ, i, j
# do something the value aₓ of a(uᵢ, vⱼ) at x, along with quadrature weight wₓ,
# for overlapping basis functions i and j
end so that A = zeros(m, n)
quadratureloop(a, U, V) do aₓ, x, wₓ, i, j
A[i,j] += aₓ * wₓ
end (This might be useful for other reasons, e.g. to use custom matrix data structures.) Then, for example, u_vec, v_vec = get_vector(u), get_vector(v)
U, V = get_space(U), get_space(V)
integral = 0.0
quadratureloop(a, U, V) do aₓ, x, wₓ, i, j
integral += aₓ * wₓ * u_vec[i] * v_vec[j]
end |
In this case, you can access the data you mention as follows. module MWE
using Gridap
function get_cell_weights(dΩ::Gridap.CellData.Measure)
get_cell_weights(dΩ.quad)
end
function get_cell_weights(quad::Gridap.CellData.CellQuadrature)
if quad.data_domain_style == PhysicalDomain() && quad.integration_domain_style == PhysicalDomain()
quad.cell_weight
elseif quad.data_domain_style == ReferenceDomain() && quad.integration_domain_style == PhysicalDomain()
cell_map = get_cell_map(quad.trian)
cell_Jt = lazy_map(∇,cell_map)
cell_Jtx = lazy_map(evaluate,cell_Jt,quad.cell_point)
cell_m = lazy_map(Broadcasting(Gridap.TensorValues.meas),cell_Jtx)
lazy_map(Broadcasting(*),quad.cell_weight,cell_m)
elseif quad.data_domain_style == ReferenceDomain() && quad.integration_domain_style == ReferenceDomain()
quad.cell_weight
else
Gridap.Helpers.@notimplemented
end
end
domain = (0,1,0,1)
cells = (4,4)
model = CartesianDiscreteModel(domain,cells)
Ω = Triangulation(model)
k = 1
dΩ = Measure(Ω,4*k) # more points than needed to make number of points different than number of local shape functions
reffe = ReferenceFE(lagrangian,Float64,k)
V = FESpace(model,reffe)
U = V
a_integrand(u,v) = ∇(u)⋅∇(v)
dv = get_fe_basis(V)
du = get_trial_fe_basis(U)
p = get_cell_points(dΩ)
cell_ax = a_integrand(du,dv)(p)
cell_w = get_cell_weights(dΩ)
cell_x = Gridap.CellData.get_array(p)
c1 = array_cache(cell_ax)
c2 = array_cache(cell_w)
c3 = array_cache(cell_x)
ncells = length(cell_ax)
for cell in 1:ncells
ax = getindex!(c1,cell_ax,cell)
w = getindex!(c2,cell_w,cell)
x = getindex!(c3,cell_x,cell)
@show cell
display(ax) # ax[q,:,:] local matrix at point q
display(w) # w[q] integration weight at point q
display(x) # x[q] physical coordinate of integration point q
end
end # module
|
This is great, Thank you Francesc! I think with this I can properly construct the gradient I need. Just to ensure I am parsing this correctly, if I wanted to compute the integral as in Steven's example above, it might look like: integral = 0.0
for cell in 1:ncells
ax = getindex!(c1,cell_ax,cell)
w = getindex!(c2,cell_w,cell)
x = getindex!(c3,cell_x,cell)
a_mat = ax * w # tensor vector product
integral += v_vec[...] * a_mat * u_vec[...] # quadratic form
end |
You still need the loop over integration points. for cell in 1:ncells
ax = getindex!(c1,cell_ax,cell)
w = getindex!(c2,cell_w,cell)
x = getindex!(c3,cell_x,cell)
for q in 1:length(w)
ax[q,:,:] # This creates a matrix, you can use a view instead
w[q]
x[q]
end
end Feel free to add the new function https://github.com/gridap/Gridap.jl/blob/master/src/CellData/DomainContributions.jl |
Gotcha, will do. I'm trying to figure out how ax[q,:,:] maps to the global matrix acquired from assemble_matrix(). I need to find the indices in u_vec and v_vec that correspond to a given cell so I can perform something similar to the following: integral = 0.0
for cell in 1:ncells
ax = getindex!(c1,cell_ax,cell)
w = getindex!(c2,cell_w,cell)
x = getindex!(c3,cell_x,cell)
for q in 1:length(w)
a_mat = ax[q,:,:] * w[q]
integral += v_vec[indices] * a_mat * u_vec[indices]
end
end Basically, I'm unsure how to get |
I would start reading some of Gridap's asssembly-related code if I were you. The files containing most of what you want are The function that sets up the assembly for matrices can be found here. The |
Hi @hammy4815, I am not sure what u_vec and v_vec are, but perhaps you are looking for something like this: uh::FEFunction
vh::FEFunction
u_vec = get_free_dof_values(uh)
v_vec = get_free_dof_values(vh)
cell_dof_ids = get_cell_dof_ids(U,\Omega)
c4 = array_cache(cell_dof_ids)
integral = 0.0
for cell in 1:ncells
ax = getindex!(c1,cell_ax,cell)
w = getindex!(c2,cell_w,cell)
x = getindex!(c3,cell_x,cell)
indices = getindex!(c4,cell_dof_ids,cell)
for q in 1:length(w)
a_mat = ax[q,:,:] * w[q]
# Following line assumes that you don't have Dirichlet BCs
# Otherwise you need to handle negative values in indices
integral += transpose(v_vec[indices]) * a_mat * u_vec[indices]
end
end This would be equivalent to A = assemble_matrix(a,U,V)
integral = transpose(v_vec)*A*u_vec |
Great! This is what I needed. Thank you! I will create a PR with the added functionality ( |
@hammy4815 and I were looking for a lower-level abstraction that gives us access to the quadrature points used when assembling a matrix. (This is for topology optimization where the degrees of freedom are specified on some external grid, not on the FE mesh.)
I think all we need is a API like the following, given a quadratic form
a
and two FEFunctionsu,v
on some meshΩ
:so that, for example,
∫a(u,v)dΩ
could be computed with:(In our case we want to do something different with the quadrature points and weights, not just an integral)
The text was updated successfully, but these errors were encountered: