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

Mesh.facets_around() not working after refinement #1154

Open
duarte-jfs opened this issue Aug 2, 2024 · 6 comments
Open

Mesh.facets_around() not working after refinement #1154

duarte-jfs opened this issue Aug 2, 2024 · 6 comments

Comments

@duarte-jfs
Copy link

I was working on the mesh refinement, trying to understand how can boundaries be kept, and came across the issue of the mesh.facets_around() not working properly after a refinement.

from collections import OrderedDict

import matplotlib.pyplot as plt
import numpy as np
import shapely
import shapely.affinity
from skfem import Basis, ElementTriP0, adaptive_theta
from skfem.io.meshio import from_meshio

from femwell.maxwell.waveguide import compute_modes, eval_error_estimator
from femwell.mesh import mesh_from_OrderedDict

polygons_paper = OrderedDict(
   left=shapely.LineString(((0, 0), (0, 1))),
   right=shapely.LineString(((1, 0), (1, 1))),
   top=shapely.LineString(((0, 1), (1, 1))),
   square=shapely.box(0.6, 0.6, 0.8, 0.8),
   core=shapely.box(0, 0, 0.5, 0.5),
   clad=shapely.box(0, 0, 1, 1),
)

boundaries = [
   [lambda x: x[0] == np.min(x[0]), lambda x: x[0] == np.max(x[0])],
   [lambda x: x[0] == np.min(x[0]), lambda x: x[0] == np.max(x[0])],
   [lambda x: x[0] == np.min(x[0]), lambda x: x[1] == np.max(x[1])],
   [lambda x: x[0] == np.min(x[0]), lambda x: x[1] == np.max(x[1])],
]

epsilons_paper = [
   {"core": 2.25, "clad": 1, 'square': 1},
   {"core": 8, "clad": 1, 'square': 1},
   {"core": 1, "clad": 2.25, 'square': 1},
   {"core": 1, "clad": 8, 'square': 1},
]

neff_values_paper = [1.27627404, 2.65679692, 1.387926425, 2.761465320]
num = 3

mesh = from_meshio(
   mesh_from_OrderedDict(polygons_paper, {}, default_resolution_max=0.1, filename="mesh.msh")
)

basis0 = Basis(mesh, ElementTriP0())
epsilon = basis0.zeros()
for subdomain, e in epsilons_paper[num].items():
   epsilon[basis0.get_dofs(elements=subdomain)] = e

modes = compute_modes(
   basis0, epsilon, wavelength=1.5, num_modes=1, order=1, metallic_boundaries=boundaries[num]
)

check_boundary(mesh)
# print(mesh.)
mesh = refined(adaptive_theta(eval_error_estimator(modes[0].basis, modes[0].E), theta=0.5))
check_boundary(mesh)

Before refinement:
image

After refinement:
image

@kinnala
Copy link
Owner

kinnala commented Aug 2, 2024

Thanks for the report. Based on this, all named boundaries should be removed from the mesh during adaptive refine:

_boundaries=None,

What is check_mesh doing?

@kinnala
Copy link
Owner

kinnala commented Aug 2, 2024

Anyhow, don’t expect this to be fixed any time soon. It is a somewhat challenging indexing problem to solve in general.

@duarte-jfs
Copy link
Author

Sorry, the check_boundary is just taking care of the plots. Getting elements coordinates and normal vectors and plotting.

Based on this, all named boundaries should be removed from the mesh during adaptive refine:

The thing is, the named boundaries are not preserved already. What is preserved is the sub domains, but the ordering may be messed up. I don't know

Anyhow, don’t expect this to be fixed any time soon. It is a somewhat challenging indexing problem to solve in general.

Yes, I can only imagine. It would be a great feature though

@kinnala
Copy link
Owner

kinnala commented Aug 6, 2024

I don't quite follow what happens in this issue. Can you provide the code of check_mesh?

@duarte-jfs
Copy link
Author

I don't quite follow what happens in this issue. Can you provide the code of check_mesh?

def check_boundary(mesh):
    plt.figure()
    plt.scatter(*mesh.p, marker = 'o', facecolor = 'None', edgecolor = 'black', s = 15)

    # boundary = mesh.boundaries['square___clad']
    boundary = mesh.facets_around(mesh.subdomains['square'])
    facet_basis = basis0.boundary(boundary)
    facets = mesh.facets[:,boundary]
    colors = plt.cm.jet(np.linspace(0,1,facets.shape[1]))
    
    
    for i in range(facets.shape[1]):
        # plt.text(*data[:,i], f'{i}')
        
    
        x = [mesh.p[0,facets[0,i]], mesh.p[0,facets[1,i]]]
        y = [mesh.p[1,facets[0,i]], mesh.p[1,facets[1,i]]]
        
    
        norm = np.asarray([facet_basis.normals[0,i,0], 
                           facet_basis.normals[1,i,0]])
        
        norm = norm/np.sqrt(np.sum(np.abs(norm)**2)) * 0.1
    
        plt.arrow(np.mean(x), np.mean(y), dx = norm[0], dy = norm[1], color = colors[i], 
                  head_width = 0.03, 
                  head_length = 0.01,
                  length_includes_head = True)
        
        plt.plot(x, y, color = colors[i])
        # plt.text(np.mean(x), np.mean(y), f"{i}")

    plt.scatter(mesh.p[0,facets[0]], mesh.p[1,facets[0]], c = colors, s = 20)
    plt.scatter(mesh.p[0,facets[1]], mesh.p[1,facets[1]], c = colors, s = 20)

@kinnala
Copy link
Owner

kinnala commented Sep 3, 2024

I'm unable to reproduce this with my own minimal example, perhaps it was fixed by another issue, or then I misunderstood the issue:

from skfem import *
import numpy as np

m = MeshTri().refined(4).with_subdomains({'test': lambda x: (x[0] < 0.5) * (x[0] > 0.3) * (x[1] < 0.5) * (x[1] > 0.3)})
m = m.with_boundaries({'test': m.facets_around('test')})
m.draw(boundaries=True).show()
m = m.refined(np.arange(200))
m = m.with_boundaries({'test': m.facets_around('test')})
m.draw(boundaries=True).show()

Before refine:
image
After refine:
image

The normal vector should be pointing opposite to the red triangle.

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

No branches or pull requests

2 participants