diff --git a/README.md b/README.md index 7a3de73f..c777beee 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,22 @@ Alternatively, if you want to skip pysdf installation, you can run the following docker build -t modulus-sym:deploy -f Dockerfile --target no-pysdf . ``` + +### Windows Container +For building windows just use +``` +docker build -t modulus - < Windows.Dockerfile +``` + +### Additional notes + +New modification suppose to work with pip to (you'll just need to install two additional libralies) +``` +pip install trimesh +pip install mesh_to_sdf +``` +Tesselation will work because instead of using pysdf I used mesh_to_sdf (I have not yet implemented sdf derivatives yet, so some functions will not work on windows (It's only a few functions for visualization differences with real data (as far as I know))) + ## Contributing For guidance on making a contribution to Modulus, see the [contributing guidelines](https://github.com/NVIDIA/modulus-sym/blob/main/CONTRIBUTING.md). @@ -78,4 +94,4 @@ For guidance on making a contribution to Modulus, see the [contributing guidelin ## License -Modulus Symbolic is provided under the Apache License 2.0, please see [LICENSE.txt](./LICENSE.txt) for full license text +Modulus Symbolic is provided under the Apache License 2.0, please see [LICENSE.txt](./LICENSE.txt) for full license text \ No newline at end of file diff --git a/Windows.Dockerfile b/Windows.Dockerfile new file mode 100644 index 00000000..82598ee7 --- /dev/null +++ b/Windows.Dockerfile @@ -0,0 +1,11 @@ +FROM nvcr.io/nvidia/modulus/modulus:23.05 + +RUN rm -rf \ + /usr/lib/x86_64-linux-gnu/libcuda.so* \ + /usr/lib/x86_64-linux-gnu/libnvcuvid.so* \ + /usr/lib/x86_64-linux-gnu/libnvidia-*.so* \ + /usr/lib/firmware \ + /usr/local/cuda/compat/lib + +RUN pip install trimesh \ + mesh_to_sdf \ No newline at end of file diff --git a/modulus/sym/geometry/tessellation.py b/modulus/sym/geometry/tessellation.py index ddb14f97..18b5a47b 100644 --- a/modulus/sym/geometry/tessellation.py +++ b/modulus/sym/geometry/tessellation.py @@ -20,14 +20,20 @@ import csv from stl import mesh as np_mesh from sympy import Symbol +import trimesh +import threading + + +from mesh_to_sdf import mesh_to_sdf + + +from copy import copy + try: import pysdf.sdf as pysdf except: - print( - "Error importing pysdf. Make sure 'libsdf.so' is in LD_LIBRARY_PATH and pysdf is installed" - ) - raise + print("sdf derivatives are not implemented yet for mesh_to_sdf") from .geometry import Geometry from .parameterization import Parameterization, Bounds, Parameter @@ -35,6 +41,60 @@ from modulus.sym.constants import diff_str +def calc_sdf_test(store_triangles, points): + global worked_thread + worked_thread = False + try: + sdf_field, sdf_derivative = libc.signed_distance_field( + store_triangles, points, include_hit_points=True + ) + except Exception as e: + print(f'pysdf doesn\'t work becayse {e}') + + else: + worked_thread = True + + +def test_pysdf(triangles, invar, airtight): + '''test if PySDF is working and if not uses mesh_to_sdf''' + + if not airtight: + return + + points = np.stack([invar["x"], invar["y"], invar["z"]], axis=1) + + # normalize triangles and points + store_triangles = np.array(triangles, dtype=np.float64) + minx, maxx, miny, maxy, minz, maxz = _find_mins_maxs(points) + max_dis = max(max((maxx - minx), (maxy - miny)), (maxz - minz)) + minx, maxx, miny, maxy, minz, maxz = _find_mins_maxs(points) + max_dis = max(max((maxx - minx), (maxy - miny)), (maxz - minz)) + store_triangles = np.array(triangles, dtype=np.float64) + store_triangles[:, :, 0] -= minx + store_triangles[:, :, 1] -= miny + store_triangles[:, :, 2] -= minz + store_triangles *= 1 / max_dis + store_triangles = store_triangles.flatten() + + points[:, 0] -= minx + points[:, 1] -= miny + points[:, 2] -= minz + points *= 1 / max_dis + points = points.astype(np.float64).flatten() + + # Create a separate thread to cath C++ execption + thread = threading.Thread(target=calc_sdf_test, + args=(store_triangles, points)) + + # Start the separate thread + thread.start() + + # Wait for the separate thread to complete + thread.join() + + return worked_thread + + class Tessellation(Geometry): """ Constructive Tessellation Module that allows sampling on surface and interior @@ -52,6 +112,14 @@ class Tessellation(Geometry): def __init__(self, mesh, airtight=True, parameterization=Parameterization()): + # test if can import PySdf + try: + import pysdf.sdf as pysdf + except: + self.pysdf_avalible = False + else: + self.pysdf_avalible = True + # make curves def _sample(mesh): def sample( @@ -111,13 +179,18 @@ def sample( invar["normal_z"] = np.concatenate(invar["normal_z"], axis=0) invar["area"] = np.concatenate(invar["area"], axis=0) + # test pysdf avalibilyty and if not use + self.pysdf_avalible = test_pysdf(mesh.vectors, invar, airtight) + # sample from the param ranges - params = parameterization.sample(nr_points, quasirandom=quasirandom) + params = parameterization.sample( + nr_points, quasirandom=quasirandom) return invar, params return sample - curves = [Curve(_sample(mesh), dims=3, parameterization=parameterization)] + curves = [Curve(_sample(mesh), dims=3, + parameterization=parameterization)] # make sdf function def _sdf(triangles, airtight): @@ -126,33 +199,56 @@ def sdf(invar, params, compute_sdf_derivatives=False): points = np.stack([invar["x"], invar["y"], invar["z"]], axis=1) # normalize triangles and points + store_triangles = np.array(triangles, dtype=np.float64) minx, maxx, miny, maxy, minz, maxz = _find_mins_maxs(points) max_dis = max(max((maxx - minx), (maxy - miny)), (maxz - minz)) - store_triangles = np.array(triangles, dtype=np.float64) - store_triangles[:, :, 0] -= minx - store_triangles[:, :, 1] -= miny - store_triangles[:, :, 2] -= minz - store_triangles *= 1 / max_dis - store_triangles = store_triangles.flatten() - points[:, 0] -= minx - points[:, 1] -= miny - points[:, 2] -= minz - points *= 1 / max_dis - points = points.astype(np.float64).flatten() + if self.pysdf_avalible: + minx, maxx, miny, maxy, minz, maxz = _find_mins_maxs( + points) + max_dis = max( + max((maxx - minx), (maxy - miny)), (maxz - minz)) + store_triangles = np.array(triangles, dtype=np.float64) + store_triangles[:, :, 0] -= minx + store_triangles[:, :, 1] -= miny + store_triangles[:, :, 2] -= minz + store_triangles *= 1 / max_dis + store_triangles = store_triangles.flatten() + + points[:, 0] -= minx + points[:, 1] -= miny + points[:, 2] -= minz + points *= 1 / max_dis + points = points.astype(np.float64).flatten() # compute sdf values outputs = {} + mesh_new = copy(mesh) + mesh_new.vectors = store_triangles if airtight: - sdf_field, sdf_derivative = pysdf.signed_distance_field( - store_triangles, points, include_hit_points=True - ) - sdf_field = -np.expand_dims(max_dis * sdf_field, axis=1) + if self.pysdf_avalible: + sdf_field, sdf_derivative = pysdf.signed_distance_field( + store_triangles, points, include_hit_points=True + ) + else: + + # compute sdf values with mesh_to_sdf + vertices = mesh_new.vectors.reshape(-1, 3) + faces = np.arange(len(vertices)).reshape(-1, 3) + + trimesh_new = trimesh.Trimesh(vertices=vertices, + faces=faces) + sdf_field = mesh_to_sdf(trimesh_new, np.squeeze( + points), surface_point_method='sample') + sdf_field = -np.expand_dims(sdf_field, axis=1) else: sdf_field = np.zeros_like(invar["x"]) outputs["sdf"] = sdf_field - + print('finished testelation') # get sdf derivatives if compute_sdf_derivatives: + if not self.pysdf_avalible: + raise Exception( + "sdf derivatives only curently work with pysdf") sdf_derivative = -(sdf_derivative - points) sdf_derivative = np.reshape( sdf_derivative, (sdf_derivative.shape[0] // 3, 3)