Skip to content

Commit caf3bd6

Browse files
committed
Add a New sheet for EBSD user input
1 parent 73b0787 commit caf3bd6

File tree

1 file changed

+195
-3
lines changed

1 file changed

+195
-3
lines changed

examples/RVE_generation/RVE_generation_GUI.py

+195-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
33
"""
4-
A Graphical User Interface for create_rve.py and cuboid_grains.py
4+
A Graphical User Interface for create_rve.py, cuboid_grains.py and cpnvert_ang2rve.py
55
Created on May 2024
6+
last Upaate Sep 2024
67
@author: Ronak Shoghi, Alexander Hartmaier
78
"""
89
import time
@@ -16,6 +17,7 @@
1617
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
1718
from kanapy.initializations import RVE_creator, mesh_creator
1819
from kanapy.entities import Simulation_Box
20+
from tkinter import filedialog
1921

2022
""" ===== Global Subroutines ===== """
2123

@@ -343,7 +345,7 @@ def export_abq(self):
343345

344346

345347
class cuboid_rve(object):
346-
""" Functions for RVEs with cuboid grains
348+
""" Functions for RVEs with cuboid grains
347349
second tab"""
348350

349351
def __init__(self):
@@ -522,6 +524,195 @@ def export_abq(self):
522524
self.create_cubes_and_plot()
523525
self.ms.write_abq('v')
524526

527+
class ebsd_rve(object):
528+
"""Functions for creating RVE from EBSD data"""
529+
530+
def __init__(self):
531+
# define standard parameters
532+
self.ebsd = None
533+
self.ms = None
534+
self.ms_stats = None
535+
self.stats_canvas = None
536+
self.rve_canvas = None
537+
self.texture_var = tk.StringVar(value="unimodal")
538+
self.matname_var = tk.StringVar(value="Simulanium")
539+
self.nvox_var = tk.IntVar(value=40)
540+
self.size_var = tk.IntVar(value=30)
541+
self.periodic_var = tk.BooleanVar(value=True)
542+
543+
if self.texture_var.get() == 'random':
544+
self.kernel_var = tk.StringVar(value="-")
545+
self.euler_var = tk.StringVar(value="-")
546+
else:
547+
self.kernel_var = tk.StringVar(value="7.5")
548+
self.euler_var = tk.StringVar(value="0.0, 45.0, 0.0")
549+
550+
self.texture_var.trace('w', self.update_kernel_var)
551+
self.texture_var.trace('w', self.update_euler_var)
552+
553+
# plot frames
554+
tab3 = ttk.Frame(notebook)
555+
notebook.add(tab3, text="EBSD Import")
556+
main_frame = ttk.Frame(tab3)
557+
main_frame.grid(row=0, column=0, sticky='nsew', padx=20, pady=20)
558+
559+
plot_frame = ttk.Frame(tab3)
560+
plot_frame.grid(row=0, column=1, sticky='nsew', padx=20, pady=20)
561+
plot_frame.rowconfigure(0, weight=1)
562+
plot_frame.columnconfigure(0, weight=1)
563+
564+
self.stats_plot_frame = ttk.Frame(plot_frame)
565+
self.stats_plot_frame.grid(row=0, column=0, sticky='nsew')
566+
567+
self.rve_plot_frame = ttk.Frame(plot_frame)
568+
self.rve_plot_frame.grid(row=1, column=0, sticky='nsew')
569+
570+
# define labels and entries
571+
line_seq = np.linspace(0, 50, dtype=int)
572+
line = iter(line_seq)
573+
ttk.Label(main_frame, text="General Parameters", font=("Helvetica", 12, "bold")) \
574+
.grid(row=next(line), column=0, columnspan=2, pady=(10, 0), sticky='w')
575+
add_label_and_entry(main_frame, next(line), "Material Name", self.matname_var, bold=False)
576+
add_label_and_entry(main_frame, next(line), "Number of Voxels", self.nvox_var, bold=False)
577+
add_label_and_entry(main_frame, next(line), "Size of RVE (in micron)", self.size_var, bold=False)
578+
add_label_and_entry(main_frame, next(line), "Periodic", self.periodic_var, entry_type="checkbox", bold=False)
579+
580+
# Orientation Parameters
581+
ttk.Label(main_frame, text="Orientation Parameters", font=("Helvetica", 12, "bold")) \
582+
.grid(row=next(line), column=0, columnspan=2, pady=(10, 0), sticky='w')
583+
add_label_and_entry(main_frame, next(line), "Texture", self.texture_var, entry_type="combobox",
584+
options=["random", "unimodal"], bold=False)
585+
add_label_and_entry(main_frame, next(line), "Kernel Half Width (degree)", self.kernel_var, bold=False)
586+
add_label_and_entry(main_frame, next(line), "Euler Angles (degree)", self.euler_var, bold=False)
587+
588+
# create buttons
589+
button_frame = ttk.Frame(main_frame)
590+
button_frame.grid(row=next(line), column=0, columnspan=2, pady=10, sticky='ew')
591+
592+
button_upload_ebsd = ttk.Button(button_frame, text="Upload EBSD File", style='TButton',
593+
command=self.upload_ebsd)
594+
button_upload_ebsd.grid(row=0, column=0, padx=(10, 5), pady=5, sticky='ew')
595+
596+
button_show_ebsd = ttk.Button(button_frame, text="Show EBSD", style='TButton')
597+
button_show_ebsd.grid(row=0, column=1, padx=5, pady=5, sticky='ew')
598+
599+
button_create_rve = ttk.Button(button_frame, text="Create RVE", style='TButton',
600+
command=self.create_rve_and_plot)
601+
button_create_rve.grid(row=1, column=0, padx=(10, 5), pady=5, sticky='ew')
602+
603+
button_create_ori = ttk.Button(button_frame, text="Create Orientations", style='TButton',
604+
command=self.create_orientation)
605+
button_create_ori.grid(row=1, column=1, padx=5, pady=5, sticky='ew')
606+
607+
write_files_button = ttk.Button(button_frame, text="Write Abaqus Input", style='TButton',
608+
command=self.export_abq)
609+
write_files_button.grid(row=2, column=0, padx=(10, 5), pady=5, sticky='ew')
610+
611+
button_exit = ttk.Button(button_frame, text="Exit", style='TButton', command=close)
612+
button_exit.grid(row=2, column=1, padx=(10, 5), pady=5, sticky='ew')
613+
614+
def update_kernel_var(self, *args):
615+
self.kernel_var.set("-" if self.texture_var.get() == 'random' else "7.5")
616+
617+
def update_euler_var(self, *args):
618+
self.euler_var.set("-" if self.texture_var.get() == 'random' else "0.0, 45.0, 0.0")
619+
620+
def upload_ebsd(self):
621+
"""Upload EBSD file."""
622+
file_path = filedialog.askopenfilename(title="Select EBSD File", filetypes=[("EBSD Files", "*.ang")])
623+
if file_path:
624+
self_closing_message("Uploading EBSD file, please wait..")
625+
self.ebsd = knpy.EBSDmap(file_path, plot=False)
626+
self.extract_microstructure_params()
627+
self_closing_message("EBSD file uploaded successfully.")
628+
def extract_microstructure_params(self):
629+
"""Extracts microstructure parameters from the EBSD data."""
630+
if self.ebsd is None:
631+
return
632+
633+
ms_data = self.ebsd.ms_data[0]
634+
gs_param = ms_data['gs_param']
635+
ar_param = ms_data['ar_param']
636+
om_param = ms_data['om_param']
637+
self.matname_var.set(ms_data['name'])
638+
639+
def create_rve_and_plot(self):
640+
"""Creates the RVE and plots it."""
641+
if self.ebsd is None:
642+
print("No EBSD file uploaded.")
643+
return
644+
self_closing_message("Creating RVE, please wait...")
645+
texture = self.texture_var.get()
646+
matname = self.matname_var.get()
647+
nvox = int(self.nvox_var.get())
648+
size = int(self.size_var.get())
649+
periodic = self.periodic_var.get()
650+
651+
ms_data = self.ebsd.ms_data[0]
652+
gs_param = ms_data['gs_param']
653+
ar_param = ms_data['ar_param']
654+
om_param = ms_data['om_param']
655+
656+
ms_stats = knpy.set_stats(gs_param, ar_param, om_param, deq_min=8.0, deq_max=19.0, asp_min=0.95, asp_max=3.5,
657+
omega_min=0.0, omega_max=np.pi, voxels=nvox, size=size, periodicity=periodic, VF=1.0,
658+
phasename=matname, phasenum=0)
659+
660+
self.ms = knpy.Microstructure(descriptor=ms_stats, name=f"{matname}_{texture}_texture")
661+
self.ms.init_RVE()
662+
self.ms.pack()
663+
self.ms.voxelize()
664+
fig = self.ms.plot_voxels(silent=True, sliced=False)
665+
self.display_plot(fig)
666+
self_closing_message("RVE created successfully.")
667+
668+
def display_plot(self, fig):
669+
"""Displays the RVE plot."""
670+
if self.rve_canvas is not None:
671+
self.rve_canvas.get_tk_widget().destroy()
672+
673+
self.rve_canvas = FigureCanvasTkAgg(fig, master=self.rve_plot_frame)
674+
self.rve_canvas.draw()
675+
self.rve_canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
676+
677+
def create_orientation(self):
678+
"""Creates orientations for the grains."""
679+
if not knpy.MTEX_AVAIL:
680+
self_closing_message("Generation of grain orientation requires MTEX module.")
681+
return
682+
self_closing_message("The process has been started, please wait...")
683+
684+
texture = self.texture_var.get()
685+
matname = self.matname_var.get()
686+
687+
if texture == 'unimodal':
688+
omega = float(self.kernel_var.get())
689+
ang_string = self.euler_var.get()
690+
ang = [float(angle.strip()) for angle in ang_string.split(',')]
691+
else:
692+
omega = None
693+
ang = None
694+
695+
if self.ms is None:
696+
self_closing_message("No RVE generated, creating RVE now.")
697+
self.create_rve_and_plot()
698+
699+
start_time = time.time()
700+
self.ms.generate_orientations(texture, ang=ang, omega=omega)
701+
fig = self.ms.plot_voxels(silent=True, sliced=False, ori=True)
702+
self.display_plot(fig)
703+
end_time = time.time()
704+
duration = end_time - start_time
705+
self_closing_message(f"Orientation created in {duration:.2f} seconds.")
706+
707+
def export_abq(self):
708+
"""Exports the RVE and orientations to an Abaqus input file."""
709+
if self.ms is None:
710+
self_closing_message("No RVE to export. Generating RVE without orientations.")
711+
self.create_rve_and_plot()
712+
713+
self.ms.write_abq('v')
714+
self_closing_message("Abaqus input file written successfully.")
715+
525716

526717
""" Main code section """
527718
app = tk.Tk()
@@ -545,4 +736,5 @@ def export_abq(self):
545736
""" Start main loop """
546737
prve = particle_rve() # First tab: Particle-based grains
547738
crve = cuboid_rve() # Second tab: Cuboid grains
548-
app.mainloop()
739+
erve = ebsd_rve() # Third tab: EBSDbased RVE
740+
app.mainloop()

0 commit comments

Comments
 (0)