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