MicroStructPy Welcome Flowchart

Python Script

The basename for this file is msp_process.py. The file can be run using this command:

microstructpy --demo=msp_process.py

The full text of the file is:

from __future__ import division

import os

import matplotlib.pyplot as plt
import microstructpy as msp
import numpy as np
from matplotlib.offsetbox import OffsetImage, TextArea, AnnotationBbox

inp_str = """
<?xml version="1.0" encoding="UTF-8"?>
<input>
    <material>
        <fraction> 0.7 </fraction>
        <area>
            <dist_type> lognorm </dist_type>
            <s> 0.5 </s>
            <scale> 0.5 </scale>
        </area>
        <color> #185A9D </color>
    </material>
    <material>
        <fraction> 0.3 </fraction>
        <shape> ellipse </shape>
        <area>
            <dist_type> uniform </dist_type>
            <loc> 0.5 </loc>
            <scale> 2 </scale>
        </area>
        <aspect_ratio> 2 </aspect_ratio>
        <angle> random </angle>
        <color> #43CEA2 </color>
    </material>
    <domain>
        <shape> rectangle </shape>
        <side_lengths> (20, 35) </side_lengths>
        <corner> (0, 0) </corner>
    </domain>
    <settings>
        <mesh_min_angle> 15 </mesh_min_angle>
        <tri_kwargs>
            <linewidth> 0.2 </linewidth>
        </tri_kwargs>
        <verify> True </verify>
    </settings>
</input>
""".lstrip()


def main():
    # Filenames
    file_dir = os.path.dirname(os.path.realpath(__file__))
    output_dir = os.path.join(file_dir, 'msp_process')

    xml_basename = 'process.xml'

    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # Write XML File
    xml_filename = os.path.join(output_dir, xml_basename)
    with open(xml_filename, 'w') as file:
        file.write(inp_str)

    # Run XML File
    in_data = msp.cli.read_input(xml_filename)
    phases = in_data['material']
    domain = in_data['domain']
    kwargs = in_data['settings']
    msp.cli.run(phases, domain, **kwargs)

    # Plot Seed Breakdowns
    seedlist_filename = os.path.join(output_dir, 'seeds.txt')
    seeds = msp.seeding.SeedList.from_file(seedlist_filename)
    plot_breakdown(seeds, phases, domain, output_dir)

    # Combine Plots
    zoom_nom = 0.086
    px_nom = 742
    w = 0.78

    fig = plt.figure()
    ax = fig.add_axes([0, 0, w, w])

    ax.set_xlim(-11, 40)
    ax.set_ylim(0.5, 10)

    ax.set_axis_off()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    # Arrow
    y_xml_bot = 5.6
    y_top = 9
    y_mid = 0.5 * (y_xml_bot + y_top)
    x_min = -6.1
    x_side = 30.4
    x_max = 35
    x_mid = 0.5 * (x_min + x_max)

    x_verif_r = x_mid + 7
    y_verif_mid = 3.7
    x_verif_l = x_mid - 7

    cstyle = "angle,angleA=180,angleB=-90,rad=0"
    ax.annotate("",
                xy=(x_side, y_mid), xycoords='data',
                xytext=(x_min, y_mid), textcoords='data',
                arrowprops=dict(arrowstyle='-|>', color="C0",
                                patchA=None, patchB=None
                                ),
                )
    ax.annotate("",
                xy=(x_max, y_xml_bot), xycoords='data',
                xytext=(x_verif_r, y_verif_mid), textcoords='data',
                arrowprops=dict(arrowstyle='<|-', color="C1",
                                patchA=None, patchB=None,
                                connectionstyle=cstyle,
                                ),
                )
    ax.annotate("",
                xy=(x_min, y_xml_bot), xycoords='data',
                xytext=(x_verif_l, y_verif_mid), textcoords='data',
                arrowprops=dict(arrowstyle='<|-', color="C1",
                                patchA=None, patchB=None,
                                connectionstyle=cstyle,
                                ),
                )

    # - Text of XML file
    ob_xml = TextArea(inp_str.rstrip(),
                      textprops={'fontsize': 2.3, 'family': 'monospace'})
    ab_xml = AnnotationBbox(ob_xml, (-10.4, 9 - 0.01), pad=0.1,
                            box_alignment=(0, 1),
                            bboxprops={'linewidth': 0.5})
    ax.add_artist(ab_xml)

    # - Seeds Plot
    arr_seeds = plt.imread(os.path.join(output_dir, 'seeds.png'))
    zoom = zoom_nom * px_nom / arr_seeds.shape[1]
    ob_seeds = OffsetImage(arr_seeds, zoom=zoom)
    ab_seeds = AnnotationBbox(ob_seeds, (0, 9),
                              pad=0, box_alignment=(0, 1),
                              bboxprops={'edgecolor': 'none'})
    ax.add_artist(ab_seeds)

    # - Breakdown Plot
    bkdwn_filename = os.path.join(output_dir, 'breakdown.png')
    remove_whitespace(bkdwn_filename)
    arr_bkdwn = plt.imread(bkdwn_filename)
    zoom = zoom_nom * px_nom / arr_bkdwn.shape[1]
    ob_bkdwn = OffsetImage(arr_bkdwn, zoom=zoom)
    ab_bkdwn = AnnotationBbox(ob_bkdwn, (10, 9),
                              pad=0, box_alignment=(0, 1),
                              bboxprops={'edgecolor': 'none'})
    ax.add_artist(ab_bkdwn)

    # - Polymesh Plot
    arr_poly = plt.imread(os.path.join(output_dir, 'polymesh.png'))
    zoom = zoom_nom * px_nom / arr_poly.shape[1]
    ob_poly = OffsetImage(arr_poly, zoom=zoom)
    ab_poly = AnnotationBbox(ob_poly, (20, 9),
                             pad=0, box_alignment=(0, 1),
                             bboxprops={'edgecolor': 'none'})
    ax.add_artist(ab_poly)

    # - Trimesh Plot
    arr_tri = plt.imread(os.path.join(output_dir, 'trimesh.png'))
    zoom = zoom_nom * px_nom / arr_tri.shape[1]
    ob_tri = OffsetImage(arr_tri, zoom=zoom)
    ab_tri = AnnotationBbox(ob_tri, (30, 9),
                            pad=0, box_alignment=(0, 1),
                            bboxprops={'edgecolor': 'none'})
    ax.add_artist(ab_tri)

    # - Verification Plot
    verif_x = x_mid
    verif_filename = os.path.join(output_dir, 'verification', 'area_cdf.png')
    remove_whitespace(verif_filename)
    arr_verif = plt.imread(verif_filename)
    zoom = zoom_nom * 0.7 * 1645 / arr_verif.shape[1]
    ob_verif = OffsetImage(arr_verif, zoom=zoom)
    ab_verif = AnnotationBbox(ob_verif, (verif_x, 2.2),
                              pad=0, box_alignment=(0.5, 0),
                              bboxprops={'edgecolor': 'none'})
    ax.add_artist(ab_verif)

    # Add Titles
    y_txt = 9.1
    off = -0.1
    fs = 9
    plt.text(x_min + 0.3, y_txt, 'Microstructure\nDescription',
             fontsize=fs, weight='bold', va='bottom', ha='center')
    plt.text(5 + off, y_txt, 'Seed\nGeometries', fontsize=fs,
             va='bottom', ha='center')
    plt.text(15 + off, y_txt, 'Multi-Circle\nApproximation', fontsize=fs,
             va='bottom', ha='center')
    plt.text(25 + off, y_txt, 'Polygonal\nMesh', fontsize=fs,
             va='bottom', ha='center')
    plt.text(35 + off, y_txt, 'Triangular\nMesh', fontsize=fs,
             weight='bold', va='bottom', ha='center')
    plt.text(verif_x + 0.7, 2.1, 'Mesh Verification', fontsize=fs,
             va='top', ha='center')

    # Save Figure
    out_filename = os.path.join(output_dir, 'process.png')
    plt.savefig(out_filename, dpi=600)
    plt.clf()

    # Remove Whitespace
    remove_whitespace(out_filename)


def plot_breakdown(seeds, phases, domain, output_dir):
    plt.clf()
    seed_colors = [phases[s.phase]['color'] for s in seeds]
    seeds.plot_breakdown(edgecolors=seed_colors, facecolor='none',
                         linewidth=0.5)

    lims = domain.limits
    plt.axis('square')
    plt.xlim(lims[0])
    plt.ylim(lims[1])
    plt.savefig(os.path.join(output_dir, 'breakdown.png'))


def remove_whitespace(filename):
    im = plt.imread(filename)
    rgb = im[:, :, :-1]
    mask = rgb.min(axis=-1) < 1
    col_mask = np.any(mask, axis=0)
    row_mask = np.any(mask, axis=1)
    row_i = np.argmax(row_mask)
    row_j = len(row_mask) - np.argmax(np.flip(row_mask)) + 2

    col_i = np.argmax(col_mask)
    col_j = len(col_mask) - np.argmax(np.flip(col_mask)) + 2

    new_im = im[row_i:row_j, col_i:col_j]
    plt.imsave(filename, new_im)


if __name__ == '__main__':
    main()

XML File

This example first writes an XML file and calls the CLI to produce the output plots. This file is saved to msp_process/process.xml.

Breakdown Plot

MicroStructPy does no produce plots of seed breakdowns by default. To include this plot in the flow chart, the SeedList.plot_breakdown() method is called, then the plot is formatted and saved.

Flowchart

The flowchart is created by loading the XML file and plots into annotation boxes, then adding arrows to connect them. The chart is shown in Fig. 27.

MicroStructPy welcome page flowchart.

Fig. 27 MicroStructPy welcome page flowchart.