Source code for gustaf.io.nutils

"""gustaf/gustaf/io/nutils.py.

io functions for nutils.
"""
import numpy as np

from gustaf.faces import Faces
from gustaf.io import mixd
from gustaf.io.ioutils import abs_fname, check_and_makedirs
from gustaf.volumes import Volumes


[docs] def load(fname): """nutils load. Loads a nutils (np.savez) file and returns a Gustaf Mesh. Parameters ----------- fname: str The npz file needs the following keys: nodes, cnodes, coords, tags, btags, ptags. Returns -------- mesh: Faces or Volumes """ npz_file = np.load(fname, allow_pickle=True) nodes = npz_file["nodes"] _ = npz_file["cnodes"] coords = npz_file["coords"] _ = npz_file["tags"].item() btags = npz_file["btags"].item() _ = npz_file["ptags"].item() if nodes.shape[0] == 0: raise TypeError("Can not find nodes. Check nutils mesh description.") if coords.shape[0] == 0: raise TypeError("Can not find coords. Check nutils mesh description.") vertices = coords # connec simplex = True connec = nodes if vertices.shape[1] == 2: volume = False else: volume = True # reshape connec try: ncol = int(3) if simplex and not volume else int(4) connec = connec.reshape(-1, ncol) mesh = Volumes(vertices, connec) if volume else Faces(vertices, connec) except BaseException: raise RuntimeError( "Can not generate a mesh from the nutils input." "Check nutils mesh description." ) mesh.BC = btags return mesh
[docs] def export(mesh, fname): """Export in Nutils format. Files are saved as np.savez(). Supports triangle,and tetrahedron Meshes. Parameters ----------- mesh: Faces or Volumes fname: str Returns -------- None """ dic = to_nutils_simplex(mesh) # prepare export location fname = abs_fname(fname) check_and_makedirs(fname) np.savez(fname, **dic)
[docs] def to_nutils_simplex(mesh): """Converts a Gustaf_Mesh to a Dictionary, which can be interpreted by ``nutils.mesh.simplex(**to_nutils_simplex(mesh))``. Only works for Triangles and Tetrahedrons! Parameters ----------- mesh: Faces or Volumes Returns -------- dic_to_nutils: dict """ vertices = mesh.vertices faces = mesh.faces whatami = mesh.whatami # In 2D, element = face. In 3D, element = volume. if whatami.startswith("tri"): dimension = 2 permutation = [1, 2, 0] elements = faces elif whatami.startswith("tet"): dimension = 3 permutation = [2, 3, 1, 0] volumes = mesh.volumes elements = volumes else: raise TypeError("Only Triangle and Tetrahedrons are accepted.") dic_to_nutils = dict() # Sort the Node IDs for each Element. sort_array = np.argsort(elements, axis=1) elements_sorted = np.take_along_axis(elements, sort_array, axis=1) # Let`s get the Boundaries bcs = dict() bcs_in = mixd.make_mrng(mesh) bcs_in = np.ndarray.reshape( bcs_in, (int(len(bcs_in) / (dimension + 1)), (dimension + 1)) ) bound_id = np.unique(bcs_in) bound_id = bound_id[bound_id > 0] # Reorder the mrng according to nutils permutation: swap columns bcs_in[:, :] = bcs_in[:, permutation] # Let's reorder the bcs file with the sort_array bcs_sorted = np.take_along_axis(bcs_in, sort_array, axis=1) for bi in bound_id: bcs[str(bi)] = np.argwhere(bcs_sorted == bi) dic_to_nutils.update( { "nodes": elements_sorted, "cnodes": elements_sorted, "coords": vertices, "tags": {}, "btags": bcs, "ptags": {}, } ) return dic_to_nutils