upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export module
Visualization & Export – Part O of the Twinned FCC walkthrough.
Covers a 3D PyVista render, a raw npy/pickle dump, and an Abaqus mesh + elsets/nodesets export. Elset/nodeset configuration is pure data (no compute step of its own) – it is all consumed by export_abaqus_mesh below via its role_enabled/role_prefix/nset_config arguments. Finishes by rendering the accumulated upxo.reporting.ReportSession to report.html.
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.render_3d_structure(cleaner, role_opacity=None, role_color=None, nonhost_cmap=None)[source]
Interactive PyVista 3D render (renders inline if called from a Jupyter notebook with PyVista’s Jupyter backend enabled; opens a separate window otherwise). No return value – this is a plotting side effect.
role_opacity/role_color default to None, which lets render_3d apply its own tuned defaults – notably primary_twin at partial opacity (0.6, not fully solid), so secondary twins nucleated at or inside the primary-twin/host interface stay visible instead of being hidden behind an opaque primary-twin surface. Pass your own dicts only if you deliberately want different opacities/colours.
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.render_ipf_slice(cleaner, axis=2, slice_idx=None, sample_direction=(0.0, 0.0, 1.0))[source]
Plots an IPF-coloured 2D slice through the cleaned structure – plain matplotlib (unlike render_3d_structure above, this has no interactive-window step and runs fine in a headless/automated execution).
axis: 0=X, 1=Y, 2=Z. slice_idx: None (default) uses the domain’s mid-slice.
- Return type:
(fig, ax)
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.sgs_pole_figure_stages(cleaner)[source]
Per-grain orientations for the five SGS (synthetic structure) pole-figure populations, matching steps_ebsd_analysis_2.ebsd_pole_figure_stages()’s shape exactly for direct pairing in steps_distribution_viewer.plot_texture_residual(): ‘full’ (every grain), ‘host’ (every non-twin grain – both allocated hosts and untouched non-hosts, the synthetic analogue of EBSD’s ‘parents’), ‘primary_twins’, ‘secondary_twins’, and ‘all_twins’.
- Returns:
dict ({‘full’, ‘host’, ‘primary_twins’, ‘secondary_twins’,)
’all_twins’} – each a {‘gids’ (ndarray, ‘quats’: ndarray}.)
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.sample_frame_quats(stage_data, apply_sample_symmetry=True, use_rd=True, use_td=True, use_nd=True)[source]
Pole-figure-ready orientations of one population.
stage_data: {‘gids’, ‘quats’} with quats in DefDAP’s passive convention (as from ebsd_pole_figure_stages()/sgs_pole_figure_stages()). The vector part is negated (crystal->sample, defdap_passive_to_active), then, with apply_sample_symmetry, every orientation is replicated through the sample-symmetry group of 180 deg rotations about the selected RD/TD/ND axes – default: all three on (4 operations).
- Returns:
(quats, gids)
- Return type:
gids tiled to match the replicated quats.
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.plot_pole_figure(stage_data, pole_family='100', plot_mode='density', half_width_deg=7.5, title=None, ax=None, apply_sample_symmetry=True, use_rd=True, use_td=True, use_nd=True, projection='stereographic', hemisphere='upper', cmap='viridis', grid_points='auto', mud_clip_min=None, mud_clip_max=None, colorbar_decimals=2, x_label='X', y_label='Y', z_label='Z')[source]
Plots one population’s pole figure – a {‘gids’, ‘quats’} dict from ebsd_pole_figure_stages()/sgs_pole_figure_stages().
plot_mode: ‘density’ (MUD contour), ‘scatter’, or ‘hybrid’ (density with an IPF-coloured scatter overlay). half_width_deg: the density kernel’s angular half-width (degrees) – ignored for plot_mode=’scatter’. apply_sample_symmetry/use_rd/use_td/use_nd: sample symmetry (default on, RD+TD+ND). Crystal (cubic) symmetry is always applied through the pole family’s symmetric equivalents. projection: ‘stereographic’ (default) or ‘equal_area’. hemisphere: ‘upper’, ‘lower’ or ‘both_mapped’ (scatter and hybrid only).
- Return type:
(fig, ax)
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.plot_pole_figure_comparison(ebsd_stage, synth_stage, ebsd_label='EBSD', synth_label='Synthetic', pole_family='111', plot_mode='scatter', apply_sample_symmetry=True, use_rd=True, use_td=True, use_nd=True, projection='stereographic', hemisphere='upper', density_cmap='viridis', diff_cmap='RdBu_r', grid_points='auto', unit_normalize=False, colorbar_decimals=2, x_label='X', y_label='Y', z_label='Z')[source]
EBSD-against-synthetic pole-figure comparison (orientation assignment and post-twin validation): three panels side by side.
plot_mode ‘scatter’ (default): EBSD | Synthetic | overlay. plot_mode ‘density’: EBSD | Synthetic MUD density on one shared colour scale, then their difference. grid_points ‘auto’ resolves to 150 so both sides share one grid. Both stages are {‘gids’, ‘quats’} in DefDAP’s passive convention; the same sample symmetry is applied to both, so their counts stay comparable. Panel titles give (grain count, plotted orientation count).
- Return type:
(fig, (ax_ebsd, ax_synth, ax_third))
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.pretwin_pole_figure_populations(rg, parent_info, base, assigner, csl_label)[source]
Populations for the pre-twin comparison (orientation assignment): EBSD ‘pure_parents’ (grains that host a twin of csl_label and are never one) and synthetic ‘hosts’ (assigned twin-host grains) and ‘all’ (every assigned grain). Each {‘gids’, ‘quats’} in DefDAP’s passive convention, ready for plot_pole_figure_comparison().
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.plot_pole_figure_overlay(stage_a, label_a, stage_b, label_b, pole_family='100', marker_a='o', marker_b='^', color_a='steelblue', color_b='darkorange', title=None, apply_sample_symmetry=True, use_rd=True, use_td=True, use_nd=True, projection='stereographic', hemisphere='upper')[source]
Overlays two populations’ scatter pole figures on one axes, distinguished by marker shape (not just colour) – e.g. parents vs. twins on the same plot. Always scatter – density contours from two different-sized populations can’t be meaningfully overlaid the same way; use plot_pole_figure() per population for density instead.
- Return type:
(fig, ax)
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.next_master_folder(output_dir=PosixPath('/home/runner/work/UPXO/UPXO/data'), base_filename='grain_structure')[source]
Picks the next unused “<base_filename><N>” folder name under <output_dir>/TwinnedFCC/Grain Structures – the collision-avoidance convention export_raw() uses by default, and the one steps_temporal_slice_sweep.sweep_temporal_slices() uses once per sweep (not once per slice) to give every slice in that sweep a shared master folder. Creates the “Grain Structures” directory if it does not already exist (needed to check what’s already there), but NOT the returned folder itself – that happens when something is actually written into it.
- Returns:
str
- Return type:
the chosen folder name (not a full path), e.g. “grain_structure3”.
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.export_raw(cleaner, output_dir=PosixPath('/home/runner/work/UPXO/UPXO/data'), base_filename='grain_structure', master_folder=None)[source]
Dumps the cleaned structure’s raw arrays (label field, orientations, twin role/parent maps) as .npy/.pkl – the lightest- weight, format-agnostic save, useful for reloading straight back into Python later without re-running the pipeline.
Files are written directly under <output_dir>/TwinnedFCC/Grain Structures/<master_folder>/. When master_folder is None (the default), a fresh, auto-numbered “<base_filename><N>” folder is picked via next_master_folder(), so repeated exports never overwrite each other. Pass an explicit master_folder (e.g. “<sweep_folder>/tslice_<key>”, as sweep_temporal_slices() does) to nest this export inside a folder shared across a whole sweep instead.
- Returns:
dict ({‘out_dir’, ‘master_folder’, ‘files’ (name -> byte size),)
’n_grains’, ‘timestamp’}
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.build_abaqus_index(cleaner, verbose=True)[source]
Builds the grain-element index the Abaqus export needs (which elements belong to which grain/role/family/variant). Cache this yourself if exporting the same cleaned structure more than once – it’s the expensive part.
- upxo.pxtal.twinned_simple_3d.steps.steps_visualization_export.export_abaqus_mesh(cleaner, tg, index, output_dir=PosixPath('/home/runner/work/UPXO/UPXO/data'), base_filename='twinned_fcc_mesh', voxel_size_um=1.0, element_type='C3D8', material_format='reference_umat', n_depvar=1, length_scale=0.001, load_axis='z', applied_strain=0.2, step_time=80.0, initial_inc=0.01, min_inc=1e-08, max_inc=1.0, max_increments=10000, output_interval=0.5, element_outputs=('LE', 'NE', 'S', 'SDV'), node_outputs=('U',), write_role_elsets=True, write_family_elsets=True, write_variant_elsets=True, role_enabled=None, role_prefix=None, family_prefix='es_family_', variant_prefix='es_variant_', nset_config=None, material_level='feature')[source]
Writes the full Abaqus .inp mesh (voxel-conformal C3D8 elements by default) plus elsets (by role/family/variant) and nodesets (domain faces), into a fresh, auto-numbered subfolder so repeated exports never overwrite each other.
index: from build_abaqus_index() above. tg: the TwinGenerator3D from steps_twin_generation.generate_twins (needed for family/variant elset provenance).
- Returns:
dict ({‘output_dir’, ‘n_elements’, ‘n_elsets’, ‘n_nsets’, ‘files’)
(name -> byte size)}