Skip to content

Commit 0d3dc06

Browse files
committed
Merge branch 'master' of https://github.com/jonwright/ImageD11
2 parents e7b75da + e727c25 commit 0d3dc06

9 files changed

Lines changed: 906 additions & 30 deletions

File tree

ImageD11/grain.py

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ def read_grain_file(filename):
376376
STRINGATTRS = ["intensity_info", "name"]
377377
NUMATTRS = ["npks", "nuniq"]
378378
ARRATTRS = ["translation"]
379-
379+
MATATTRS = ["UB", "ubi", "B", "U", "mt", "rmt"]
380380

381381
def write_grain_file_h5(filename, list_of_grains, group_name='grains'):
382382
"""Write list of grains to H5py file."""
@@ -410,3 +410,125 @@ def read_grain_file_h5(filename, group_name='grains'):
410410
grains.append(g)
411411

412412
return grains
413+
414+
415+
def export_to_vtp_paraview(grains, output_path, colour='npks'):
416+
"""
417+
Export list of grains to vtp file for Paraview visualisation, with helpful arrays included.
418+
Thanks to Marilyn Sarkis for the idea.
419+
"""
420+
import vtk
421+
from vtk.util import numpy_support as ns
422+
from scipy.spatial.transform import Rotation as R
423+
424+
def add_scalar_attribute(pd, attr, np_array):
425+
"""Add scalar attribute array to polydata"""
426+
attr_array = ns.numpy_to_vtk(np_array, deep=True)
427+
attr_array.SetName(attr)
428+
pd.GetPointData().AddArray(attr_array)
429+
430+
def add_vector_attribute(pd, attr, np_array):
431+
"""Add vector attribute array to polydata"""
432+
attr_array = ns.numpy_to_vtk(np_array, deep=True)
433+
attr_array.SetNumberOfComponents(np_array.shape[1]) # required for vectors
434+
attr_array.SetName(attr)
435+
pd.GetPointData().AddArray(attr_array)
436+
437+
# ensure we have ipf colours
438+
rgbattr = 'rgb_z'
439+
try:
440+
col = [getattr(grain, rgbattr) for grain in grains] # IPF colour
441+
except AttributeError:
442+
# couldn't get the IPF attributes
443+
# try to compute it first
444+
# will still fail if we don't have reference unitcells
445+
from ImageD11.nbGui.nb_utils import get_rgbs_for_grains
446+
get_rgbs_for_grains(grains)
447+
col = [getattr(grain, rgbattr) for grain in grains] # IPF colour
448+
449+
translations = np.array([grain.translation for grain in grains])
450+
451+
points = vtk.vtkPoints()
452+
verts = vtk.vtkCellArray()
453+
454+
for i, t in enumerate(translations):
455+
pid = points.InsertNextPoint(t[0], t[1], t[2])
456+
verts.InsertNextCell(1)
457+
verts.InsertCellPoint(pid)
458+
459+
polydata = vtk.vtkPolyData()
460+
polydata.SetPoints(points)
461+
polydata.SetVerts(verts)
462+
463+
# add scalar attributes to polydata
464+
for numattr in NUMATTRS:
465+
np_array = np.array([float(getattr(grain, numattr)) for grain in grains])
466+
add_scalar_attribute(polydata, numattr, np_array)
467+
468+
# compute volumes
469+
prop_volumes = np.array([float(grain.intensity_info.split("mean = ")[1].split(" , ")[0].replace("'", "")) for grain in grains])
470+
prop_radii = np.cbrt(3*prop_volumes/(4*np.pi))
471+
472+
add_scalar_attribute(polydata, 'prop_volume', prop_volumes)
473+
add_scalar_attribute(polydata, 'prop_radius', prop_radii)
474+
475+
# add vector attributes (e.g. colours)
476+
for vecattr in ["rgb_x", "rgb_y", "rgb_z", "Rod", "unitcell"]:
477+
np_array = np.array([getattr(grain, vecattr) for grain in grains])
478+
add_vector_attribute(polydata, vecattr, np_array)
479+
480+
# compute quaternions for glyph orientation in Paraview
481+
482+
quats = R.from_matrix([g.U for g in grains]).as_quat(scalar_first=True) # WXYZ order to match Paraview
483+
484+
add_vector_attribute(polydata, 'quat', quats)
485+
486+
# it's also useful to have lab-frame vector fields for (x_c, y_c, z_c) and (a, b, c) and (astar, bstar, cstar) for viz
487+
# x_c, y_c, z_c are columns of U
488+
add_vector_attribute(polydata, "x_c", np.array([g.U[:, 0] for g in grains]))
489+
add_vector_attribute(polydata, "y_c", np.array([g.U[:, 1] for g in grains]))
490+
add_vector_attribute(polydata, "z_c", np.array([g.U[:, 2] for g in grains]))
491+
492+
# a, b, c are rows of UBI (because we invert)
493+
add_vector_attribute(polydata, "a", np.array([g.ubi[0, :] for g in grains]))
494+
add_vector_attribute(polydata, "b", np.array([g.ubi[1, :] for g in grains]))
495+
add_vector_attribute(polydata, "c", np.array([g.ubi[2, :] for g in grains]))
496+
497+
# a*, b*, c* are columns of UB
498+
add_vector_attribute(polydata, "astar", np.array([g.UB[:, 0] for g in grains]))
499+
add_vector_attribute(polydata, "bstar", np.array([g.UB[:, 1] for g in grains]))
500+
add_vector_attribute(polydata, "cstar", np.array([g.UB[:, 2] for g in grains]))
501+
502+
# add matrix attributes
503+
for matattr in MATATTRS:
504+
tensor_components = [
505+
('11', 0, 0), ('12', 0, 1), ('13', 0, 2),
506+
('21', 1, 0), ('22', 1, 1), ('23', 1, 2),
507+
('31', 2, 0), ('32', 2, 1), ('33', 2, 2)
508+
]
509+
for comp_name, i, j in tensor_components:
510+
attr_name = "{}_{}".format(matattr, comp_name)
511+
np_array = np.array([getattr(grain, matattr)[i, j] for grain in grains])
512+
add_scalar_attribute(polydata, attr_name, np_array)
513+
514+
eps_s = np.array([grain.eps_sample_matrix(dzero_cell=grain.ref_unitcell.lattice_parameters) for grain in grains])
515+
eps_c = np.array([grain.eps_grain_matrix(dzero_cell=grain.ref_unitcell.lattice_parameters) for grain in grains])
516+
517+
# it's a strain tensor, so we can name them xx, yy, zz etc
518+
tensor_components = [
519+
('xx', 0, 0), ('xy', 0, 1), ('xz', 0, 2),
520+
('yx', 1, 0), ('yy', 1, 1), ('yz', 1, 2),
521+
('zx', 2, 0), ('zy', 2, 1), ('zz', 2, 2)
522+
]
523+
for comp_name, i, j in tensor_components:
524+
add_scalar_attribute(polydata, "eps_s_{}".format(comp_name), eps_s[:,i,j])
525+
add_scalar_attribute(polydata, "eps_c_{}".format(comp_name), eps_c[:,i,j])
526+
527+
# set the active scalars
528+
polydata.GetPointData().SetActiveScalars(colour)
529+
530+
# export to file
531+
writer = vtk.vtkXMLPolyDataWriter()
532+
writer.SetFileName(output_path)
533+
writer.SetInputData(polydata)
534+
writer.Write()

0 commit comments

Comments
 (0)