dtcc-platform / dtcc

DTCC Platform
MIT License
0 stars 4 forks source link

Compute mesh quality indicators #62

Closed anderslogg closed 7 months ago

anderslogg commented 1 year ago

We need to compute metrics including the following:

anderslogg commented 1 year ago

@dwastberg Should this be in dtcc-builder or dtcc-wrangler?

Georspai commented 1 year ago

@anderslogg , @vbassn , I've made a Python implementation for the above quality metrics. The main issue was that while there is a concensus on the meaning of each indicator there are different definitions for their computation.

I describe the methods I used for each indicator to get some feedback before starting the C++ implementation.

For Surface Meshes:

1. Aspect Ratio

In meshes with triangular faces is computed by measuring the ratio of the longest edge length to the shortest edge length within a triangle. A lower aspect ratio indicates a more regular and well-shaped triangle.

Aspect Ratio = L_max / L_min

2. Orthogonality

I measured a face's orthogonality as the minimum deviation of its angles from a right angle. The closer this indicator is to 0, the closer the face resembles a right triangle.

        oi_0 = abs(1 - (angle_between(AC, AB) / (np.pi / 2)))
        oi_1 = abs(1 - (angle_between(AB, BC) / (np.pi / 2)))
        oi_2 = abs(1 - (angle_between(AC, BC) / (np.pi / 2)))

        orthogonality[i] = min((oi_0, oi_1, oi_2))

3. Skewness

As a measure for skewness I used equiangular skew.

`Equiangle Skew = max(Θmax- Θc)/(180-θc),(Θc-Θmin)/θc)`

where:
- Θmax : is the largest angle in a face or cell
- Θmin : is the smallest angle in a face or cell
- θc :   is the angle for equi-angular face or cell i.e. 60 for a triangle and 90 for a square.

4. Smoothness

Smoothness measures the change in size between neighbour faces of the mesh. In the case of a surface mesh I measured smoothness as the standard deviation in area of all faces adjacent to a Vertex.

For Volume Meshes:

1. Aspect Ratio

I used three different metrics for AR in Volume Meshes:

  1. As in surface meshes, checking the ratio of the longest edge length to the shortest edge length. Edge length check provides a lazy aspect ratio indicator for tetrahedron cells

  2. Measuring AR as the Ratio of the longest edge length to the length of the inradius of the tetrahedron cell.

  3. Measuring AR as the Ratio of the Circumradius of the tetrahedron cell to the inradius of the tetrahedron cell.

2. Orthogonality

As a metric for orthogonality I computed the normals of the cells faces and measure orthogonality as the RMS of the dot products between the cell's normals. We could potentially also use the dot products of opposite edges of the tetrahedron.

3. Skewness

As a measure of skewness for tetrahedron cells I used the ratio:

Skewness = (V_ideal - V) / V_ideal

Where:

4. Smoothness

Smoothness measures the change in size between neighbour cells of the mesh. In the case of a volume mesh I measured smoothness as the standard deviation in volume of all cells adjacent to a Vertex.

The functions above return arrays with metrics for each cell or vertex for further statistical analysis. Additionally, we can define specific thresholds for each indicator, helping us determine what constitutes a 'good' mesh.

anderslogg commented 1 year ago

@Georspai Great job and thanks for the complete and very informative overview. I think the next step should be to use the Python implementation on a couple of test cases (2-3 meshes) and compare the 4 indicators to what Mariya gets with Fluent. If possible, try choose the same indicators as in Fluent to get the exact same results. Then we have a working Python reference implementation that we know is correct. Then it's a matter of porting that to C++ and veryfying again that it gives the same as in Python.

vbassn commented 10 months ago

@anderslogg actually the only missing thing is how to enable them in options. @Georspai has come up with a binary solution, but I am not really convinced.

Georspai commented 10 months ago

@anderslogg @vbassn Since all parameters are mostly booleans , ints and some strings for paths, I wanted to follow the same mentality and use ints for the parameters that pick which metrics are going to be measured. I used the same logic as linux file permissions.

_parameters = {}

_parameters["model_name"] = "DTCC"
_parameters["auto_domain"] = True
_parameters["debug"] = False

_parameters["build_mesh"] = True
_parameters["build_volume_mesh"] = True

_parameters["save_protobuf"] = True
_parameters["save_json"] = False
_parameters["save_shp"] = False
_parameters["save_vtk"] = False
_parameters["save_stl"] = False
_parameters["save_obj"] = False

_parameters["ground_smoothing"] = 3

_parameters["metrics_report_level"] = 45 
_parameters["metrics_report_level_volume"] = 927

def default():
    return _parameters.copy()

Essentially, we have: Surface Meshes: 6 metrics, so the level ranges from 0 to 63. Volume Meshes: 4 Cell-Based Metrics and 6 Face-Based Metrics, so the report level ranges from 0 to 1023.

In this case: The metrics_report_level 45 is 101101, meaning all metrics except the second and the second last. The metrics_report_level_volume 927 is 1110011111, meaning all metrics except the sixth and the seventh. When the level is zero, the "quick" check runs, which includes the two most significant metrics.

But upon some discussion with Vasilis, we realize that this design is concise but not user friendly at all. So I would like to discuss some other solution for how the parameter indicating the metrics should be.

vbassn commented 10 months ago

@Georspai thanks! @anderslogg how do you feel about the options?

anderslogg commented 9 months ago

@Georspai @vbassn I don't think the binary system works. It's too cryptic. Is the problem that we need to pass too many parameters down the chain from the Python layer to C++?

It makes more sense to be explicit about the parameters. That also fills an additional purpose which is to expose which metrics are available, something like this:

_parameters["report_mesh_metric_aspect_ratio"] = True
_parameters["report_mesh_metric_orthogonality"] = False
...
_parameters["report_volume_mesh_metric_aspect_ratio"] = True
_parameters["report_volume_mesh_metric_orthogonality = False
...