Closed fmonteghetti closed 2 years ago
I am aware of this issue. The MPCs, being as general as they are, does not sanity check the constraints. i.e., if you constrain a degree of freedom twice, you need to remove one of the constraints.
As create_periodic_constraint_*
simply appends data to a numpy array: https://github.com/jorgensd/dolfinx_mpc/blob/master/python/dolfinx_mpc/multipointconstraint.py#L162
An additional check could be added here that checks if the input slaves are already in another constraint. However, this is a slippery slope, as the next sane step would be to check that no slave degree of freedom is a master in another constraint, i.e.
c_i = b c_j
c_j = d c_k
which should be simplified to
c_i = c_k
c_j = c_k
If one wants this kind of nested behaviour, the setup-time for the assemblers would grow with the number of constraints.
To summarize:
A way to work around this is by creating a single periodic constraint for both of the edges in your problem, and create a mapping that depends on the geometrical coordinates. I.e. for a square: (mapping left ->right), (bottom to top)
def mapping(x):
left_constraint = x[1] > 1e-14
mapped_values = np.zeros((2, x.shape[1]))
mapped_values[0] = left_constraint + x[0]
mapped_values[1] = np.invert(left_constraint) + x[1]
return mapped_values
This means that if the coordinates of the dofs on the facet is on the left side (excluding top right corner) they will be mapped from (0, y) to (1, y) and (x, 0) to (x, 1).
Thanks a lot for your answer, I will try to make this work on the unit square demo and report back. It sounds like it would be worth turning this into a demo, since studies of periodic media commonly encounter this case.
I typically work with models where the slave and master boundaries are identified with tags provided by gmsh, rather than geometrical equations. So, in principle, I know directly the slave and master dofs that are to be mapped by each periodic boundary condition, as well as the dofs that are over-constrained.
Is there a way to use this information to avoid embedding geometrical tolerances in the definition of the periodic boundary condition?
For example, a lower-level way could be to provide dolfinx_mpc with the slave and master dofs directly. It would then be the responsibility of the user to ensure that no dofs appear twice, but this is easy to check. Is this possible right now?
Thanks a lot for your answer, I will try to make this work on the unit square demo and report back. It sounds like it would be worth turning this into a demo, since studies of periodic media commonly encounter this case.
I typically work with models where the slave and master boundaries are identified with tags provided by gmsh, rather than geometrical equations. So, in principle, I know directly the slave and master dofs that are to be mapped by each periodic boundary condition, as well as the dofs that are over-constrained.
Is there a way to use this information to avoid embedding geometrical tolerances in the definition of the periodic boundary condition?
For example, a lower-level way could be to provide dolfinx_mpc with the slave and master dofs directly. It would then be the responsibility of the user to ensure that no dofs appear twice, but this is easy to check. Is this possible right now?
The lower level way of adding a constraint is: https://github.com/jorgensd/dolfinx_mpc/blob/8abd427d6d909cc2883d4e45ee04cb080db2fe40/python/dolfinx_mpc/multipointconstraint.py#L39-L60 The complicated bit is to get the global number of the master dof, as this might live on another process that then slave dof. What the wrappers do is to do this in a scalable way, with MPI neighborhood communicators.
Thanks a lot for you help, I really appreciate it. I need to read your MPI magic! :)
The suggested workaround works: in demo_periodic_gep_modified.py, we can keep two calls to create_periodic_constraint_topological()
as long as the slave_to_master_map of the second periodic boundary condition excludes dofs that belong to either the slave or master boundary of the previous periodic boundary condition. I will send a modified demo when I have a clean implementation.
By the way, is there a clean way to test x[0]>1e-14
? In the fenics days I relied on fenics.near(x[0],0)
.
For future readers, here is a description of the workaround.
--- Workaround to enforce N periodic boundary conditions
Currently, a user calling create_periodic_constraint_topological()
several times can end up with a wrong computation without any warnings or errors. One way to apply N periodic boundary conditions reliably is to define:
I_slave[n]: x -> bool
that identifies the n-th slave boundary. I_master[n]: x -> bool
that identifies the n-th master boundary.slave_to_master[n]: x -> x
that maps the n-th slave boundary to the n-th master boundary.The user must ensure that slave_to_master[n]
excludes dofs that are master or slaves of one of the n-1 previously applied periodic boundary conditions (i.e. dofs that satisfy I_slave[k][x]==True
or I_master[k]==True
for k<n). This can be done by sending excluded dofs outside the mesh (there may be a cleaner way).
---
The workaround is consistent with fenics usage, where one must provide (1,2,3). However, in fenics the user does not need to manually exclude slave or master dofs of the previously applied boundary conditions.
My understanding is that if create_periodic_constraint_topological()
is modified to accept a way of identifying the master boundary, then all the information would be there to safely apply N periodic boundary conditions within dolphin_mpc. But changing the API is clearly not ideal.
demo_periodic_gep_modified.zip
Here is a modified demo_periodic_gep.py that demonstrates the workaround described above. It produces the correct eigenvalues (including multiplicities) in dokken92/dolfinx_mpc:v0.4.1. The two modifications are:
create_periodic_constraint_topological()
by re-defining pbc_vert_slave_to_master_map
. This syntax generalizes to N periodic boundary conditions easily (put the periodic boundary conditions in a list and loop over the previous ones).numpy.nan
. If you agree with these modifications, then perhaps this could be added as a demo, or I could merge it with demo_periodic_gep.py.
The existing demo_periodic_gep.py tests whether diagval
works, while the attached demo_periodic_gep_modified.py demonstrates how to use multiple periodic boundary conditions, which could be useful to people interested in periodic media moving from fenics to fenicsx.
Feel free to make a pull request
Demo illustrating how to handle this has been added in #22
Hi Jørgen,
I came across this issue while investigating regression in some of my models.
Issue: Problems with multiple periodic boundary conditions may not be accurately discretized if there are nodes common to several periodic boundaries.
Reproduction steps: Run the attached demo_periodic_gep_modified.py in dokken92/dolfinx_mpc:v0.4.1 and
Background: demo_periodic_gep_modified.py computes the eigenvalues of the Laplacian on the unit square with two periodic boundary conditions: the left edge is mapped to the right edge and the bottom edge is mapped to the top edge. The four corner nodes (0,0), (0,1), (1,0), and (1,1) belong to two different periodic boundary conditions.
Comparing the fenics and dolfinx_mpc results shows that dolfinx_mpc is accurate only for eigenfunctions that are null at all of the corner nodes, while fenics has no such issue. This can be seen on the first eigenfunction u_00, which should be constant, as well as on u_04 and u_08.
Observations and suggestions:
While investigating this I have made two observations:
[1] dolfinx 2019.2.9.99 / dolfinx_mpc 4c9b04c4678d0f36c0a819c2892cc73c7a5f85ab.
Here are some uneducated suggestions:
create_periodic_constraint_topological()
is not designed to be called twice, and an alternative strategy should be used to deal with multiple periodic boundary conditions.Attachment: issue-double-pbc.zip