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

Utility for symmetric metric #155

Open
ddundo opened this issue Oct 22, 2024 · 12 comments
Open

Utility for symmetric metric #155

ddundo opened this issue Oct 22, 2024 · 12 comments
Labels
enhancement New feature or request

Comments

@ddundo
Copy link
Member

ddundo commented Oct 22, 2024

I think that it would be useful to add a utility to make the metric symmetric, as we'd want to sometimes have a symmetric mesh (when the problem is symmetric). I guess we can do this easily by copying the metric, rotating it and then taking the mean of the two?

@ddundo ddundo added the enhancement New feature or request label Oct 22, 2024
@jwallwork23
Copy link
Member

Is it not sufficient to just apply the enforce_spd method?

@jwallwork23
Copy link
Member

Oh hang on, do you mean symmetric in space rather than within the entries at a given point?

@ddundo
Copy link
Member Author

ddundo commented Oct 22, 2024

Ah sorry for not being clear! I did mean in space, yes - so that the generated mesh would be symmetric.

@ddundo
Copy link
Member Author

ddundo commented Oct 22, 2024

And I think my suggestion would only work if the original mesh is symmetric so that the new and old nodes would still align after the transformation

Also saw this repo now https://github.com/MmgTools/MirrorMesh

@ddundo
Copy link
Member Author

ddundo commented Oct 29, 2024

Hey @jwallwork23, could you please tell me what you think about the workflow below? I modified the simple_metric.py animate demo to get this. In particular, I was wondering if there is a way to make a deepcopy of a mesh rather than redefining it (labelled below with TODO)?

from firedrake import *
from firedrake.pyplot import *
import matplotlib.pyplot as plt
from animate import *

mesh = UnitSquareMesh(40, 40)
P1_ten = TensorFunctionSpace(mesh, "CG", 1)
metric = RiemannianMetric(P1_ten)

x, y = SpatialCoordinate(mesh)
r = 0.4
h1 = 0.02
h2 = 0.05
high = as_matrix([[1 / h1**2, 0], [0, 1 / h1**2]])
low = as_matrix([[1 / h2**2, 0], [0, 1 / h2**2]])
metric.interpolate(conditional(sqrt((x - 0.3) ** 2 + (y - 0.3) ** 2) < r, high, low))
density, *_ = metric.density_and_quotients()

# TEMPORARY METRIC ON A ROTATED DOMAIN
mesh_rotated = UnitSquareMesh(40, 40)  # TODO: Can we make a deepcopy of mesh?
P1_ten_rotated = TensorFunctionSpace(mesh_rotated, "CG", 1)
metric_rotated_temp = RiemannianMetric(P1_ten_rotated)
metric_rotated_temp.interpolate(metric)
mesh_rotated.coordinates.dat.data[:] = 1 - mesh_rotated.coordinates.dat.data

# INTERPOLATE TEMPORARY ROTATED METRIC ON THE ORIGINAL MESH
metric_rotated = RiemannianMetric(P1_ten)
metric_rotated.interpolate(metric_rotated_temp)
density_rotated, *_ = metric_rotated.density_and_quotients()

# COMPUTE SYMMETRIC METRIC ON THE ORIGINAL MESH
metric_symmetric = RiemannianMetric(P1_ten)
metric_symmetric.assign(0.5 * (metric + metric_rotated))
density_symmetric,*_ = metric_symmetric.density_and_quotients()

amesh = adapt(mesh, metric)
amesh_rotated = adapt(mesh, metric_rotated)
amesh_symmetric = adapt(mesh, metric_symmetric)

fig, axes = plt.subplots(2, 3, figsize=(10, 6.5), sharex=True, sharey=True)
axes[0, 0].set_title("Metric density")
tripcolor(density, axes=axes[0, 0])
axes[0, 1].set_title("Rotated m. density")
tripcolor(density_rotated, axes=axes[0, 1])
axes[0, 2].set_title("(Density + Rotated density)/2")
tripcolor(density_symmetric, axes=axes[0, 2])

triplot(amesh, axes=axes[1, 0])
triplot(amesh_rotated, axes=axes[1, 1])
triplot(amesh_symmetric, axes=axes[1, 2])
for ax in axes.flatten():
    ax.set_xlim(0, 1)
    ax.set_ylim(0, 1)
    ax.set_aspect("equal")
plt.show()

image

@jwallwork23
Copy link
Member

Would it not be sufficient to just interpolate the rotated metric rather than rotating the mesh and interpolating between meshes?

To copy a mesh I normally do Mesh(old_mesh.coordinates.copy(deepcopy=True)).

@ddundo
Copy link
Member Author

ddundo commented Oct 29, 2024

Would it not be sufficient to just interpolate the rotated metric rather than rotating the mesh and interpolating between meshes?

That won't work if old_mesh isn't symmetric to begin with, since rotated vertices wouldn't match up with existing (not rotated) vertices. So in that case we need to interpolate between meshes. Or am I misunderstanding? If so, could you code/pseudocode what you mean please? :)

To copy a mesh I normally do Mesh(old_mesh.coordinates.copy(deepcopy=True)).

Thanks, but that doesn't seem to create a deepcopy unfortunately (the above example doesn't work). I'll dig more :)

@ddundo
Copy link
Member Author

ddundo commented Oct 29, 2024

And just a sidenote... having a symmetric metric doesn't guarantee at all that the mesh will be symmetric. But it should be close enough.

@jwallwork23
Copy link
Member

Thanks, but that doesn't seem to create a deepcopy unfortunately (the above example doesn't work). I'll dig more :)

How about Mesh(Function(old_mesh.coordinates))?

@jwallwork23
Copy link
Member

jwallwork23 commented Oct 29, 2024

That won't work if old_mesh isn't symmetric to begin with, since rotated vertices wouldn't match up with existing (not rotated) vertices. So in that case we need to interpolate between meshes. Or am I misunderstanding? If so, could you code/pseudocode what you mean please? :)

But even with rotating the mesh you still interpolate back into $\mathbb{P}1$ space on the old mesh, so it isn't going to be fully symmetric. I can see that a similar approach would work if you took a supermesh of the old mesh and rotated mesh.

@jwallwork23
Copy link
Member

Please could you clarify in what sense you want the metric to be symmetric? I was under the impression you wanted it to be symmetric (e.g.) in the $x$-axis, i.e., invariant to reflection top <-> bottom. But the discussion above refers to rotation, which is a different kind of transformation.

@ddundo
Copy link
Member Author

ddundo commented Oct 29, 2024

Will start by saying that if you think this isn't something worth spending time on at the moment, please don't waste time thinking about it. I am just working on this for my lock exchange case and thought I'd implement it here while it's fresh, but can get back to it later :)

How about Mesh(Function(old_mesh.coordinates))?

Sadly not. When I do mesh_rotated = Mesh(Function(mesh.coordinates.copy(deepcopy=True))), the mesh_rotated still seems to use mesh.coordinates.

But even with rotating the mesh you still interpolate back into P 1 space on the old mesh, so it isn't going to be fully symmetric. I can see that a similar approach would work if you took a supermesh of the old mesh and rotated mesh.

Ah great point with supermeshing! And yes, sorry - I am assuming that the original mesh isn't horribly asymmetric.

Please could you clarify in what sense you want the metric to be symmetric? I was under the impression you wanted it to be symmetric (e.g.) in the x -axis, i.e., invariant to reflection top <-> bottom. But the discussion above refers to rotation, which is a different kind of transformation.

In my specific case (lock exchange) I indeed want to have 180deg rotational symmetry. But I thought that this approach is quite general if we wanted to add this utility to animate: transform the metric in whatever way (reflect, rotate...) and take the mean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants