-
Notifications
You must be signed in to change notification settings - Fork 16
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
GSoC Task #2: Implement aggregation method for vector-valued problems #153
Comments
In this file there are different ways of computing the "strength" graph of a sparse matrix, also for vector-valued problems: |
@fverdugo @oriolcg @amartinhuertas |
you can either export it from the package or to use |
Meeting notes from 2024-06-20: Attendees: @fverdugo @GeliezaK Action Points:
|
Meeting notes from 2024-06-27: Attendees: @fverdugo @GeliezaK @oriolcg @amartinhuertas Action Points:
|
Hi @GeliezaK I realize that function function add_block_size_to_aggregates(node_to_aggregate,aggregates,block_size)
naggregates = length(aggregates)
nnodes = length(node_to_aggregate)
ndofs = nnodes*block_size
dof_to_aggregate = zeros(Int32,ndofs)
for node in 1:nnodes
aggregate = node_to_aggregate[node]
for i in 1:block_size
dof = (node-1)*block_size + i
dof_to_aggregate[dof] = (aggregate-1)*block_size + i
end
end
dof_to_aggregates, 1:(naggregates*block_size)
end |
Hi @GeliezaK , yet another edit. I don't think we need a "constant prolongator" with block size > 1. I ralized this after looking at Algorithm 7, page 46, here: https://mediatum.ub.tum.de/download/1229321/1229321.pdf We need to build the "node based" constant prolongator just like now, and implement a tentative prolongater that takes into account the block size and the near null space (Algorithm 7). Somehting like this: function coarsen(A,B)
G = strength_graph(A,block_size)
diagG = dense_diag(G)
node_to_aggregate, aggregates = aggregate(G,diagG;epsilon)
PC = constant_prolongator(node_to_aggregate, aggregates,1)
P0,Bc = tentative_prolongator_with_block_size(PC,B,block_size) # Algorithm 7
...
end |
NB. When qr is mentioned in Algorithm 7, it is really a "thin" QR decomposition. See section for rectangular matrices here: https://en.wikipedia.org/wiki/QR_decomposition This discussion is relevant on how to compute the thin qr in Julia |
Hi @fverdugo , |
You are correct, but note that you cannot use node_to_aggregate directly. This vector gives you for each node the corresponding aggregate. You need the inverse map: for an aggregate you want the list of nodes in this aggregate. This info is encoded in the CSC storage of the constant_prolongator. In any case, What we actually want is this other function than returns a JaggedArray (a vector of vectors) instead of the constant_prolongator: Note that the code is almost identical than for the constant_prolongator function collect_nodes_in_aggregate(node_to_aggregate,aggregates)
typeof_aggregate = eltype(node_to_aggregate)
nnodes = length(node_to_aggregate)
pending = typeof_aggregate(0)
isolated = typeof_aggregate(-1)
nnodes = length(node_to_aggregate)
naggregates = length(aggregates)
aggregate_to_nodes_ptrs = zeros(Int,naggregates+1)
for node in 1:nnodes
agg = node_to_aggregate[node]
if agg == pending
continue
end
aggregate_to_nodes_ptrs[agg+1] += 1
end
length_to_ptrs!(aggregate_to_nodes_ptrs)
ndata = aggregate_to_nodes_ptrs[end]-1
aggregate_to_nodes_data = zeros(Int,ndata)
for node in 1:nnodes
agg = node_to_aggregate[node]
if agg == pending
continue
end
p = aggregate_to_nodes_ptrs[agg]
aggregate_to_nodes_data[p] = node
aggregate_to_nodes_ptrs[agg] += 1
end
rewind_ptrs!(aggregate_to_nodes_ptrs)
aggregate_to_nodes = jagged_array(aggregate_to_nodes_data,aggregate_to_nodes_ptrs)
aggregate_to_nodes
end
|
I don't have an answer for this at this moment. We can always merge singleton aggregates with a neighboring one until there are no singleton aggregates left. This will work if the mesh has at least 2 nodes. |
Meeting notes from 2024-07-04: Notes:
Action Points:
|
Meeting notes from 2024-07-11: Attendees: @GeliezaK @oriolcg @amartinhuertas @fverdugo Action Points:
|
Meeting notes from 2024-07-18: Action Points:
|
Meeting notes from 2024-07-25: Notes:
Action Points:
|
@GeliezaK @amartinhuertas Regarding the bug discussed on the meeting on 2024-08-15. This works for me with PartitionedArrays v0.5.2: using PartitionedArrays
nodes_per_dir = (4,4,4)
parts_per_dir = (2,2,2)
p = prod(parts_per_dir)
ranks = DebugArray(LinearIndices((p,)))
args = linear_elasticity_fem(nodes_per_dir,parts_per_dir,ranks)
A = psparse(args...) |> fetch
x = pones(partition(axes(A,2)))
b = A*x
@assert collect(b) ≈ centralize(A)*collect(x) In fact the sparse matrix-vector product was already been used in the tests
My guess is that you are modifying some of the data in |
@GeliezaK Can you please send your minimal reproducer? |
This is the minimal reproducer that we discussed yesterday: parts_per_dir = (2,1)
p = prod(parts_per_dir)
ranks = DebugArray(LinearIndices((p,)))
nodes_per_dir = (4,1)
args = PartitionedArrays.linear_elasticity_fem(nodes_per_dir,parts_per_dir,ranks)
A = psparse(args...) |> fetch
x = node_coordinates_unit_cube(nodes_per_dir,parts_per_dir, ranks)
B = near_nullspace_linear_elasticity(x, partition(axes(A,2)))
x_exact = pones(partition(axes(A,2)))
b = A*x_exact # error EDIT: The error does not happen if A is multiplied with x_exact before constructing the nullspace. |
I can reproduce the error. I know hot to fix it. |
Fixed in JuliaLang/julia#166 |
Thank you very much @fverdugo ! It's working now. |
I would like to implement a kind of allreduce with PartitionedArrays to get in each process an Array global_to_owner = reduction(.+, global_to_owner_local, init=zeros(Int,n_global_coarse_dofs), destination=rank)
How can I achieve this with PartitionedArrays? I need to pass |
Take a look how the dof partition is build from a node partition here: PartitionedArrays.jl/src/gallery.jl Line 389 in 11ded45
Maybe you can even use the same code, or just calling the |
Thank you! It works now, I did not realize there was a global_to_owner implementation. |
There seems to be some kind of bug in the code when calling This code level_params = amg_level_params_linear_elasticity(block_size;
coarsening = PartitionedSolvers.smoothed_aggregation_with_block_size(;)
)
fine_params = amg_fine_params(;level_params)
solver_le = amg(;fine_params) produces these results when compared with a scalar preconditioner: Whereas this code level_params = amg_level_params_linear_elasticity(block_size;
#coarsening = PartitionedSolvers.smoothed_aggregation_with_block_size(;)
)
fine_params = amg_fine_params(;level_params)
solver_le = amg(;fine_params) leads to calling the coarsen() function only once, but the setup runtimes are much longer and the convergence looks like this My debugger unfortunately crashes on VSCode and I can't figure out what is the problem. |
Can you share the entire code? Also how you set up the preconditioner. The blue line of the first figure looks really good. This is what we want to report. Francesc |
This is the entire code @fverdugo : |
It seems that you are using block_size == 1 internally in the first case and block_size == 3 in the second case. Thus, I would say that there is some issue in the new code for block_size !=1. I would check
|
Update: it is not necessary to change epsilon>0, it also works with epsilon==0 if in strength_graph, the blocks with norm==0 are ignored (i.e. set to 0). I pushed the code and updated the images in the final PR. |
Meeting notes 2024-06-13:
@oriolcg
Attendees: @fverdugo @amartinhuertas @GeliezaK
Notes:
Action Points:
The text was updated successfully, but these errors were encountered: