CHLNDDEV / oceanmesh

Automatic coastal ocean mesh generation in Python and C++. **under development**
GNU General Public License v3.0
55 stars 15 forks source link

Support for multiscale mesh sizing functions #33

Closed krober10nd closed 3 years ago

krober10nd commented 3 years ago

For the third item in the list above, perhaps the generate_mesh function could detect the domain is "multiscale" through the signed_distance_function object and call a modified initial point generator?

krober10nd commented 3 years ago

I've rethought the multiscale technique the last couple days. Now the approach is hopefully simpler and avoids any significant modification of the generate_mesh routine or API to build meshes.

The merging operation still is buggy and needs work and we need proper tests.

Here are some key notes:

  1. A multiscale_sizing_function https://github.com/CHLNDDEV/oceanmesh/blob/4d25f4dc132fa61377f42c804de78635267f6214/oceanmesh/edgefx.py#L221 is generated which consists of looping over each individual function and taking the minimum value at all points in the domain. The inner nests are smoothed into the outer ones using an inverse distance weighting approach in lieu of grading the entire thing as we had done previously. Further, now there is more control regarding how the nests get blended into the parent domain as compared to the Matlab version.

  2. A multiscale_signed_distance_function https://github.com/CHLNDDEV/oceanmesh/blob/4d25f4dc132fa61377f42c804de78635267f6214/oceanmesh/signed_distance_function.py#L177 is created. Here there were some significant improvements by leveraging signed distance function operations (see https://github.com/CHLNDDEV/oceanmesh/blob/4d25f4dc132fa61377f42c804de78635267f6214/oceanmesh/signed_distance_function.py#L97) . For instance, the parent domain is defined as the union of all signed distance functions and the nests are defined as the difference of the domain and all the subsequent nests (this assumes the domains are listed in order of descending minimum mesh sizes).

  3. The user calls generate_multiscale_mesh https://github.com/CHLNDDEV/oceanmesh/blob/4d25f4dc132fa61377f42c804de78635267f6214/oceanmesh/mesh_generator.py#L83 to build the multiscale mesh, which is a thin wrapper for generate_mesh by passing a list of signed distance functions and a list of edge length functions. The function loops over each domain and edge function and generates a mesh sequentially. In this way, we reuse a lot of code and don't introduce any logic to handle the multiscale case inside generate_mesh. This operation of generating the nests sequentially could be parallelized whereby each domain is sent to a thread, but that would be future work. Afterwards, a merging step takes place by hot starting the mesh generation with the combination of all points from all the domains and using the parents' domain and sizing function.

 import numpy as np

 import oceanmesh as om

 fname1 = "gshhg-shp-2.3.7/GSHHS_shp/f/GSHHS_f_L1.shp"

 bbox1, min_edge_length1 = (-75.000, -70.001, 40.0001, 41.9000), 1e3

 bbox2, min_edge_length2 = (
     np.array(
         [
             [-74.25, 40.5],
             [-73.75, 40.55],
             [-73.75, 41],
             [-74, 41],
             [-74.25, 40.5],
         ]
     ),
     250.0,
 )

 s1 = om.Shoreline(fname1, bbox1, min_edge_length1)
 sdf1 = om.signed_distance_function(s1)
 el1 = om.distance_sizing_function(s1, max_edge_length=5e3)

 s2 = om.Shoreline(fname1, bbox2, min_edge_length2)
 sdf2 = om.signed_distance_function(s2)
 el2 = om.distance_sizing_function(s2)

 points, cells = om.generate_multiscale_mesh([sdf1, sdf2], [el1, el2], plot=5)

om.plot_mesh(points, cells, pause=9999)