krober10nd / SeismicMesh

2D/3D serial and parallel triangular mesh generation tool for finite element methods.
https://seismicmesh.readthedocs.io/
GNU General Public License v3.0
127 stars 33 forks source link

support for immersed domains #114

Closed krober10nd closed 3 years ago

krober10nd commented 4 years ago
 import SeismicMesh
 import meshio

 ball = SeismicMesh.Ball([0.0, 0.0, 0.0], 1.0)
 ball2 = SeismicMesh.Ball([0.0, 0.0, 0.0], 0.5)

 points, cells = SeismicMesh.generate_mesh(
     domain=ball,
     bbox=(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0),
     edge_length=0.10,
     subdomain=[ball2],
 )
 meshio.write_points_cells(
     "ball_inside_ball.vtk",
     points,
     [("tetra", cells)],
     file_format="vtk",
 )

immersed

krober10nd commented 4 years ago

immersed2

 import SeismicMesh
 import meshio

 ball = SeismicMesh.Ball([0.0, 0.0, 0.0], 1.0)
 ball2 = SeismicMesh.Ball([0.0, 0.0, 0.0], 0.5)

 points, cells = SeismicMesh.generate_mesh(
     domain=ball,
     edge_length=0.10,
     subdomain=[ball2],
 )

 meshio.write_points_cells(
     "ball_inside_ball.vtk",
     points,
     [("tetra", cells)],
     point_data={"sd": ball2.eval(points)},
     file_format="vtk",
 )
krober10nd commented 4 years ago

Immersed_Torus

 import SeismicMesh
 import meshio

 ball = SeismicMesh.Ball([0.0, 0.0, 0.0], 1.0)
 cube2 = SeismicMesh.Cube((-0.5, 0.5, -0.5, 0.5, -0.5, 0.5))
 torus = SeismicMesh.Torus(r1=0.25, r2=0.10)

 hmin = 0.01

 points, cells = SeismicMesh.generate_mesh(
     domain=ball,
     edge_length=lambda x: hmin + 0.1 * (x[:, 0] ** 2 + x[:, 1] ** 2 + x[:, 2] ** 2),
     h0=hmin,
     subdomains=[torus],
 )

 meshio.write_points_cells(
     "torus_inside_ball.vtk",
     points,
     [("tetra", cells)],
     point_data={"sd": torus.eval(points)},
     file_format="vtk",
 )
krober10nd commented 3 years ago
 import SeismicMesh
 import meshio

 cube1 = SeismicMesh.Cube((-1.0, 1.0, -1.0, 1.0, -1.0, 1.0))
 cube2 = SeismicMesh.Cube((-2.0, 0.5, -2.5, 0.5, -2.5, 0.5))

 hmin = 0.10

 union = SeismicMesh.Union([cube1, cube2])

 points, cells = SeismicMesh.generate_mesh(
     domain=union,
     edge_length=hmin,  # lambda x: hmin + 0.05 * (x[:, 0] ** 2 + x[:, 1] ** 2 + x[:, 2] ** 2),
     h0=hmin,
     subdomains=[cube2],
     verbose=2,
     max_iter=100,
 )

 meshio.write_points_cells(
     "out.vtk",
     points,
     [("tetra", cells)],
     point_data={"sd": cube2.eval(points)},
     file_format="vtk",
 )

boxes_intersection

krober10nd commented 3 years ago

In 2D

 import meshio
 import SeismicMesh

 box0 = SeismicMesh.Rectangle((0.0, 1.0, 0.0, 1.0))
 disk0 = SeismicMesh.Disk([0.5, 0.5], 0.25)

 points, cells = SeismicMesh.generate_mesh(
     domain=box0, edge_length=0.10, subdomains=[disk0]
 )
 meshio.write_points_cells(
     "immersed_disk.vtk",
     points,
     [("triangle", cells)],
     file_format="vtk",
 )

immersed_disk

krober10nd commented 3 years ago

@jorgensd perhaps this feature would be useful for topology optimization? maybe you have some suggestions?

lgtm-com[bot] commented 3 years ago

This pull request fixes 1 alert when merging 4c8953c339c2fb552b8e1539b2106e2f29c54ecd into 6bbd5e576460d2771cdb750f0c62d8df283822fe - view on LGTM.com

fixed alerts:

jorgensd commented 3 years ago

@jorgensd perhaps this feature would be useful for topology optimization? maybe you have some suggestions?

This is quite interesting, not only for topology optimization, but for multiphysics problems as fluid structure interaction, and multi material problems in for instance elasticity.

It can of course also be used in topology/shape optimization to track domain changes. Will it be possible to have multiple level sets intersecting with a background level set (this would be something similar to gmsh's boolean fragments feature)?

krober10nd commented 3 years ago

Will it be possible to have multiple level sets intersecting with a background level set (this would be something similar to gmsh's boolean fragments feature)?

Maybe. I'm not quite sure I understand what that Gmsh boolean feature does.

In my case, the subdomain to be immersed is just simply a SDF which avoids the need to have explicit geometry information regarding its immersed boundary.

So in the example above I just create a disk but I could also immerse the union/intersection/difference of any number of SDFs using the SeismicMesh.geometry stuff:

 import meshio

 import SeismicMesh

 box0 = SeismicMesh.Rectangle((0.0, 1.0, 0.0, 1.0))
 disk0 = SeismicMesh.Disk([0.5, 0.5], 0.25)
 sqr0 = SeismicMesh.Rectangle((0.5, 0.75, 0.5, 0.75))

 domain = SeismicMesh.Union([disk0, sqr0])

 hmin = 0.0025

 fh = lambda p: 0.05 * np.abs(domain.eval(p)) + hmin

 points, cells = SeismicMesh.generate_mesh(
     domain=box0,
     edge_length=fh,
     h0=hmin,
     subdomains=[domain],
 )

 pmid = points[cells].sum(1) / 3  # Compute centroids
 sd = domain.eval(pmid)

 tags = np.zeros((len(cells))) + 10
 tags[sd < 0] = 11

 meshio.write_points_cells(
     "immersed_disk.msh",
     points,
     cells=[("triangle", cells)],
     field_data={"OutsideDisk": np.array([10, 2]), "InsideDisk": np.array([11, 2])},
     cell_data={
         "gmsh:physical": np.array([tags]),  # np.array([np.repeat(11, len(cells))]),
         "gmsh:geometrical": np.array([tags]),  # np.array([np.repeat(1, len(cells))]),
     },
     file_format="gmsh22",
     binary=False,
 )
Screen Shot 2020-11-17 at 6 33 57 PM Screen Shot 2020-11-17 at 6 33 52 PM
lgtm-com[bot] commented 3 years ago

This pull request fixes 1 alert when merging 08044d4744962445ab0b3f576b7c3d479b433602 into 6bbd5e576460d2771cdb750f0c62d8df283822fe - view on LGTM.com

fixed alerts: