├── CA_GUI_back_end.py ├── total_matrix_2D_ABAQUS.npy ├── CPU time, single core vs MPI.xlsx ├── SLM_simulated 316 SS by Andro.png ├── README.md ├── SLM_simulated 316 SS by Andro (2).png ├── link za EBSD inverse pole algoritem.txt ├── CA_GUI.py ├── setup.py ├── merging_meshes.py ├── grain_orientation_backup.py ├── random_selection.py ├── agnieszka_PA_code.py ├── domain_size_reduction.py ├── cube_rotation.py ├── grain_size_distribution_JSON.py ├── Stackoverflow_Pool_question.py ├── make_movie.py ├── get_color.py ├── fast_image_saver.py ├── MPI_pool_toycode.py ├── override_CA_long_track_backup.py ├── nova_paralelizacija.py ├── matrix_interpolation_toycode.py ├── orientation_weight_coefficient.py ├── combine_pictures.py ├── matrix_interpolation_special.py ├── pool_toycode.py ├── Long_track_CA_backup.py ├── matrix_interpolation.py ├── MPI_domain_splitting.py ├── nucleation_backup.py ├── grain_growth_2D_Abaqus.py ├── Slicer_Machine.py ├── grain_growth_2D_Abaqus_to_3D.py └── jump_over_np_pad.py /CA_GUI_back_end.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | 3 | root=Tk() 4 | -------------------------------------------------------------------------------- /total_matrix_2D_ABAQUS.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androsan/CAFE/HEAD/total_matrix_2D_ABAQUS.npy -------------------------------------------------------------------------------- /CPU time, single core vs MPI.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androsan/CAFE/HEAD/CPU time, single core vs MPI.xlsx -------------------------------------------------------------------------------- /SLM_simulated 316 SS by Andro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androsan/CAFE/HEAD/SLM_simulated 316 SS by Andro.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CAFE 2 | Python script for numerical simulation of grain-growth during solidification of 3D printed metals 3 | -------------------------------------------------------------------------------- /SLM_simulated 316 SS by Andro (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/androsan/CAFE/HEAD/SLM_simulated 316 SS by Andro (2).png -------------------------------------------------------------------------------- /link za EBSD inverse pole algoritem.txt: -------------------------------------------------------------------------------- 1 | https://mathematica.stackexchange.com/questions/47492/how-to-create-an-inverse-pole-figure-color-map -------------------------------------------------------------------------------- /CA_GUI.py: -------------------------------------------------------------------------------- 1 | from tkinter import * 2 | import builtins 3 | 4 | root = Tk() 5 | 6 | var0 = IntVar() 7 | 8 | lab0 = Label(root, textvariable=var0); lab0.grid(row=100, column=100) 9 | 10 | 11 | from Long_track_CA_NEW import * 12 | #from CA_GUI_back_end import * 13 | 14 | var0.set(i) 15 | 16 | print(a) 17 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from cx_Freeze import setup, Executable 2 | 3 | base = None 4 | 5 | executables = [Executable("Long_track_CA_NEW_GUI.py", base=base)] 6 | 7 | packages = ["os", "json", "idna", "tkinter", "subprocess", "psutil"] 8 | options = { 9 | 'build_exe': { 10 | 'packages':packages, 11 | }, 12 | } 13 | 14 | setup( 15 | name = "SLM Microstructure Simulation", 16 | options = options, 17 | version = "1.0", 18 | description = 'CA model by Andro, IMT, May 2021', 19 | executables = executables 20 | ) 21 | -------------------------------------------------------------------------------- /merging_meshes.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | seznam_premikov = ['left', 'right', 'down', 'up'] 4 | 5 | init = np.zeros((3,3)); init[1,1]=1 6 | 7 | left = init.copy() ; left[1,0]=1 8 | right = init.copy() ; right[1,2]=1 9 | down = init.copy(); down[2,1]=1 10 | up = init.copy() ; up[0,1]=1 11 | 12 | 13 | def merging_meshes(prva,druga): 14 | tot = np.where(druga==0, prva, druga) 15 | return tot 16 | 17 | right=merging_meshes(left,right) 18 | down=merging_meshes(right,down) 19 | up=merging_meshes(down,up) 20 | 21 | print(up) 22 | 23 | 24 | -------------------------------------------------------------------------------- /grain_orientation_backup.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math 3 | import matplotlib.pyplot as plt 4 | plt.ion() 5 | 6 | 7 | rp = 100 8 | 9 | def get_color(x,y): 10 | u = 1-x 11 | v = x-y 12 | w = y 13 | rgb = np.array([u,v,w]) 14 | RGB = 255*rgb/np.max(rgb) 15 | return RGB.astype('int') 16 | 17 | def random_xy_tilt(posibilities): 18 | #x = np.random.uniform(0,1) 19 | #y = np.random.uniform(0,1) 20 | xran = np.random.randint(0, posibilities+1) 21 | x = xran / posibilities 22 | y = np.random.randint(0, xran+1)/posibilities 23 | return x,y 24 | 25 | 26 | #x,y = random_xy_tilt(rp) 27 | 28 | x = 0.5 29 | y = 0 30 | 31 | rgb = get_color(x,y) 32 | alfa = math.degrees(math.atan(x))- 9.7356103173*x*y 33 | beta = math.degrees(math.atan(y))- 9.7356103173*x*y 34 | 35 | A = np.zeros((1,1,3)).astype('int') 36 | A[0,0]=rgb 37 | plt. imshow(A) 38 | plt.title(u"\u03B1 = "+str(round(alfa, 3))+u"\u00B0"+' , '+u"\u03B2 = "+str(round(beta, 3))+u"\u00B0", fontsize=18) 39 | 40 | -------------------------------------------------------------------------------- /random_selection.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import random 3 | 4 | def random_selection(x, erase): 5 | global item 6 | if len(x)!=0: 7 | item = random.choice(x) 8 | if erase: 9 | x=np.delete(x,np.where(x==item)) 10 | else: 11 | pass 12 | 13 | return x 14 | 15 | 16 | smeri = np.array(['001', '00-1', '010', '0-10', '100', '-100',]) 17 | grain_ID = np.array([1,2,]) 18 | GD = {} 19 | for gid in grain_ID: 20 | GD[gid] = smeri.copy() 21 | 22 | 23 | selekcija=[] 24 | 25 | 26 | while True: 27 | if any(grain_ID): 28 | grain_ID = random_selection(grain_ID, False) 29 | grain = item 30 | counter = 0 31 | else: 32 | break 33 | while counter==0: 34 | if any(GD[grain]): 35 | GD[grain] = random_selection(GD[grain], True) 36 | s = item 37 | print(20*'-') 38 | print('zrno: ',grain) 39 | print('smer: ',s) 40 | selekcija.append((grain,s)) 41 | counter+=1 42 | break 43 | else: 44 | grain_ID=grain_ID[grain_ID!=grain] 45 | break 46 | 47 | continue 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /agnieszka_PA_code.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | Z=2 4 | X=3 5 | Y=3 6 | 7 | z_ = np.arange(Z) 8 | x_ = np.arange(X) 9 | y_ = np.arange(Y) 10 | 11 | z, x, y = np.meshgrid(z_, x_, y_, indexing='ij') 12 | assert np.all(z[:,0,0] == z_) 13 | assert np.all(x[0,:,0] == x_) 14 | assert np.all(y[0,0,:] == y_) 15 | 16 | ZXY = np.column_stack([z.flat, x.flat, y.flat]) 17 | ZXY = ZXY.reshape((Z, X, Y, 3)) 18 | 19 | CA = ZXY+0.5 # Creating matrix of coordinates (z,x,y) of nodes in the center of CA cells 20 | 21 | epsilon = 0.49 # Scaling value, should be in between 0 and 0.49 22 | rand = np.random.uniform(0,1) # Random float between 0 and 1 23 | R = np.random.uniform(0, 1, (Z,X,Y,3)) # Matrix of random float values between 0 and 1 24 | 25 | PA = np.zeros((Z,X,Y,3)) # Creating matrix of coordinates (z,x,y) of nodes displaced from the CA cells center for random z,x,y values 26 | PA[:,:,:,0] = CA[:,:,:,0] + epsilon*(2*R[:,:,:,0] - 1) 27 | PA[:,:,:,1] = CA[:,:,:,1] + epsilon*(2*R[:,:,:,1] - 1) 28 | PA[:,:,:,2] = CA[:,:,:,2] + epsilon*(2*R[:,:,:,2] - 1) 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /domain_size_reduction.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | ''' 3 | a= np.zeros((5,5,5)) 4 | 5 | a[0,0,1]=1 6 | a[1,0,1]=1 7 | a[1,1,1]=1 8 | a[1,1,0]=1 9 | a[1,1,2]=1 10 | 11 | n = [] 12 | for i in range(a.shape[0]): 13 | t=np.where(np.all(a[i]==0, axis=0)) 14 | n.append([t[0], len(t[0])]) 15 | 16 | 17 | m=np.array(n) 18 | v = m[np.min(m[:,1])==m[:,1]][0][0] 19 | 20 | #v=np.array([0,1,2,3,8,9,10,11]) 21 | #v=np.array([8,9,10,11]) 22 | 23 | if v[0]!=0: 24 | v=np.insert(v, 0, 0) 25 | dx = np.diff(v) 26 | bol=v[:-1][dx!=1] 27 | limits=(None, v[bol[0]+1]) 28 | 29 | else: 30 | dx = np.diff(v) 31 | bol=v[:-1][dx!=1] 32 | limits=(v[bol[0]]+1, v[bol[0]+1]) 33 | 34 | 35 | 36 | b = a[:,:, limits[0]: limits[1]] 37 | 38 | 39 | for i in range(b.shape[0]): 40 | t=np.where(np.all(b[i]==0, axis=1)) 41 | print(t[0]) 42 | ''' 43 | 44 | d=np.zeros((3,3,3)) 45 | 46 | d[0,1,1]=1 47 | d[0,0,1]=1 48 | 49 | d[1,1,1]=1 50 | d[1,1,2]=1 51 | 52 | d[2,1,2]=1 53 | d[2,1,1]=1 54 | d[2,1,0]=1 55 | 56 | 57 | 58 | ax2=np.where(np.any(d==1, axis=2)) 59 | ax1=np.where(np.any(d==1, axis=1)) 60 | ax0=np.where(np.any(d==1, axis=0)) 61 | 62 | Z_lim = (np.min(ax2[0]), np.max(ax2[0])+1) 63 | X_lim = (np.min(ax2[1]), np.max(ax2[1])+1) 64 | Y_lim = (np.min(ax1[1]), np.max(ax1[1])+1) 65 | 66 | f= d[Z_lim[0]:Z_lim[1], X_lim[0]:X_lim[1], Y_lim[0]:Y_lim[1]] 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /cube_rotation.py: -------------------------------------------------------------------------------- 1 | import math 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from numpy.linalg import multi_dot 5 | from mpl_toolkits.mplot3d import Axes3D 6 | plt.ion() 7 | 8 | cube = np.array([ 9 | [1, 0, 0], 10 | [0, 1, 0], 11 | [0, 0, 1] 12 | ]) 13 | 14 | def Rotate_the_Cube(alpha, beta): 15 | global RmX, RmY 16 | cube = np.array([ 17 | [1, 0, 0], 18 | [0, 1, 0], 19 | [0, 0, 1] 20 | ]) 21 | 22 | RmY = np.array([ # rotation matrix around Y-axis 23 | [math.cos(math.radians(alpha)), 0, math.sin(math.radians(alpha))], 24 | [0, 1, 0], 25 | [-math.sin(math.radians(alpha)), 0, math.cos(math.radians(alpha))], 26 | ]) 27 | 28 | RmX = np.array([ # rotation matrix around X-axis 29 | [1, 0, 0], 30 | [0, math.cos(math.radians(beta)), math.sin(math.radians(beta))], 31 | [0, - math.sin(math.radians(beta)), math.cos(math.radians(beta))], 32 | ]) 33 | 34 | oix = multi_dot([cube, RmY, RmX]) 35 | 36 | return oix 37 | 38 | 39 | """********************""" 40 | alfa = 45 41 | beta = 45 42 | """**************""" 43 | 44 | c = Rotate_the_Cube(alfa,beta) 45 | ca = np.array([[0,0,0], c[0], c[1], c[2], c[0]+c[1], c[1]+c[2], c[0]+c[2], c[0]+c[1]+c[2]]) 46 | ogli = [(0,1), (0,2), (0,3), (1,4), (2,4), (2,5), (4,7), (1,6), (3,6), (3,5), (5,7), (6,7)] 47 | 48 | def edges(p,q): 49 | edge = [[ca[p][0], ca[q][0]], [ca[p][1], ca[q][1]], [ca[p][2], ca[q][2]]] 50 | return edge 51 | 52 | fig = plt.figure() 53 | ax = fig.add_subplot(111, projection='3d') 54 | 55 | '''------------- fake bounding box ----------------''' 56 | ax.set_aspect('equal') 57 | max_range = 2 58 | Xb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][0].flatten() 59 | Yb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][1].flatten() 60 | Zb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][2].flatten() 61 | for xb, yb, zb in zip(Xb, Yb, Zb): 62 | ax.plot([xb], [yb], [zb], 'w') 63 | ''' -----------------------------------------------------''' 64 | 65 | ax.scatter(ca[:,0], ca[:,1], ca[:,2], marker='o', s=80, color='blue') 66 | for i in ogli: 67 | rob = edges(i[0],i[1]) 68 | ax.plot(rob[0], rob[1], rob[2], color='red') 69 | 70 | ax.set_xlabel('X') 71 | ax.set_ylabel('Y') 72 | ax.set_zlabel('Z') 73 | -------------------------------------------------------------------------------- /grain_size_distribution_JSON.py: -------------------------------------------------------------------------------- 1 | import json 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | import pandas as pd 5 | plt.ion() 6 | 7 | case = 'SLM_2D_Source' ; subcase = '0002' 8 | PATH = 'C:/sm-2018-w64-0-3/WORK/'+case+'_Files/post processing database/'+subcase+'/' 9 | 10 | mapa = 'INTER time=40, space=8 Z[7-8], X[15-27], Y[12-97], 1500°C, N=12/' 11 | 12 | JSON_folder = 'Tracks (0,1,2) zipped/' 13 | JSON_root = 'nuclei_data_tracks_(0,1,2)' 14 | 15 | pixel_size = 0.625 # unit: micrometer 16 | pixel_area = pixel_size**2 # unit: square micrometer 17 | 18 | 19 | with open(PATH+mapa+'Track_0/nuclei_data.json')as grains: 20 | g = json.load(grains) 21 | df0 = pd.DataFrame.from_dict(g, orient='index') 22 | 23 | with open(PATH+mapa+'Track_1/nuclei_data_tracks_(0,1).json')as grains: 24 | g = json.load(grains) 25 | df1 = pd.DataFrame.from_dict(g, orient='index') 26 | 27 | with open(PATH+mapa+JSON_folder+JSON_root+'.json')as grains: 28 | g = json.load(grains) 29 | df2 = pd.DataFrame.from_dict(g, orient='index') 30 | 31 | G0 = df0['grain size'] 32 | G1 = df1['grain size'] 33 | G2 = df2['grain size'] 34 | 35 | G = np.concatenate((G0,G1,G2)) 36 | 37 | #G_pix = df['grain size'] # grain size - number of pixels 38 | #G_area = G_pix * pixel_area # grain size - area 39 | 40 | #a,b = np.histogram(G_area) 41 | ''' 42 | neg_xrang=1 43 | xrang_poz=10 44 | bin_sajz = 0.1 45 | x_manual = [i*bin_sajz for i in range(int(neg_xrang/bin_sajz), int(xrang_poz/bin_sajz))] 46 | plt.hist(G_area, bins=x_manual ) 47 | ''' 48 | #x=[i/10 for i in range(0, 535*10, 10)] 49 | #plt.plot(x, G_area, marker = 'o') 50 | 51 | 52 | ''' 53 | x_manual = [i*bin_sajz for i in range(int(neg_xrang/bin_sajz), int(xrang_poz/bin_sajz))] 54 | plt.figure(figsize=(12,8)) 55 | a,b = np.histogram(podatki, x_manual) 56 | max_bin_index = np.where(a == a.max()) 57 | highest = round(b[max_bin_index[0][0]], 2) 58 | plt.hist(podatki, bins=x_manual,edgecolor='white', label='Povprečje: '+str(highest)+' '+enota) 59 | plt.legend(loc='upper right', fontsize=20) 60 | plt.title(naslov_grafa+'\n'+file) 61 | plt.xlabel(ime_osi_X, fontsize=18); plt.ylabel(ime_osi_Y, fontsize=18) 62 | plt.xticks(fontsize=14); plt.yticks(fontsize=14) 63 | if save_graph: 64 | new_file = ime_grafa+'_'+file[:-4]+'.png' 65 | try: 66 | plt.gcf().savefig(direktorij+'/Histogrami'+'/'+new_file) 67 | except FileNotFoundError: 68 | os.mkdir(direktorij+'/Histogrami') 69 | plt.gcf().savefig(direktorij+'/Histogrami'+'/'+new_file) 70 | ''' 71 | 72 | -------------------------------------------------------------------------------- /Stackoverflow_Pool_question.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Pool, Manager 2 | from functools import partial 3 | import numpy as np 4 | 5 | def G(a, b): 6 | Q=b[0] 7 | R=b[1] 8 | 9 | if R == '001': 10 | a= np.where((a==0)&(np.pad(a,((0,0),(0,0), (1,0)), 'constant')[:,:,:-1]==Q) , Q, a) 11 | elif R == '00_1': 12 | a= np.where((a==0)&(np.pad(a,((0,0),(0,0), (0,1)), 'constant')[:,:,1:]==Q), Q, a) 13 | elif R == '010': 14 | a= np.where((a==0)&(np.pad(a,((0,0),(1,0), (0,0)), 'constant')[:,:-1,:]==Q), Q, a) 15 | elif R == '0_10': 16 | a= np.where((a==0)&(np.pad(a,((0,0),(0,1), (0,0)), 'constant')[:,1:,:]==Q), Q, a) 17 | 18 | 19 | return a 20 | 21 | 22 | Selection = [(8, '001'), (8, '00_1'), (8, '010'), (8, '0_10')] 23 | 24 | """ 25 | # 1st option ---------------------------------------------------- 26 | A = np.zeros((1,5,5)); A[0,2,2]=8 27 | for s in Selection: 28 | A = G(A, s) 29 | print('Result is OK, but 1st method is NOT:'); print('A=',A); print() 30 | #------------------------------------------------------------------ 31 | 32 | # 2nd option ---------------------------------------------------- 33 | A = np.zeros((1,5,5)); A[0,2,2]=8 34 | GP = partial(G, A) 35 | for s in Selection: 36 | A = GP(s) 37 | print('Result is wrong and 2nd method, too:'); print('A=',A); print() 38 | #------------------------------------------------------------------ 39 | 40 | # 3rd option ---------------------------------------------------- 41 | A = np.zeros((1,5,5)); A[0,2,2]=8 42 | for s in Selection: 43 | GP = partial(G, A) 44 | A = GP(s) 45 | print('Result is OK, but 3rd option is NOT:'); print('A=',A); print() 46 | #------------------------------------------------------------------ 47 | 48 | # 4th option ---------------------------------------------------- 49 | A = np.zeros((1,5,5)); A[0,2,2]=8 50 | GP = partial(G, A) 51 | A = map(GP, Selection) 52 | print('Result is NOT, but the 4th method is OK:'); print('A=',list(A)); print() 53 | #------------------------------------------------------------------ 54 | """ 55 | 56 | # 5th option is MPI (calculated using multi-cores by multiprocessing module) 57 | A = np.zeros((1,5,5)); A[0,2,2]=8 58 | if __name__ =='__main__': 59 | pool=Pool() 60 | manager=Manager() 61 | A=manager.list(A) 62 | 63 | for i in range(3): 64 | GP = partial(G, A) 65 | GP_list = pool.map(GP, Selection) 66 | for j in range(len(GP_list)-1): 67 | if j==0: 68 | A=np.where(GP_list[j+1]==0, GP_list[j], GP_list[j+1]) 69 | else: 70 | A=np.where(GP_list[j+1]==0, A, GP_list[j+1]) 71 | print('Result and method are OK:'); print('A=',A); print() 72 | 73 | pool.close() 74 | pool.join() 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /make_movie.py: -------------------------------------------------------------------------------- 1 | """ Creating a .AVI video of CA grain growth, melt-pool and temperature field -----------------------------""" 2 | 3 | import numpy as np 4 | import cv2 5 | 6 | case = 'SLM_2D_Source' ; subcase = '0002/' 7 | 8 | #mapa = 'INTER time=40, space=8 Z[7-8], X[15-27], Y[12-97], 1500°C, N=12/' 9 | mapa = 'INTER time=1, space=8 Z[0-9], X[15-27], Y[12-97], 1500°C, N=12/' 10 | 11 | 12 | track = 'Track_12_layers/' # for zipping False only (combining cut figures of individual track..) 13 | 14 | 15 | PATH = 'C:/sm-2018-w64-0-3/WORK/'+case+'_Files/post processing database/'+subcase+mapa+track 16 | 17 | mapa_animacija = 'animacija_rgb/' # 'animacija_rgb_bessel/' 18 | koren_slike = 'RGB_final, Z= ' # 'RGB_final bessel, Z= ' 19 | 20 | ime_videa = '3D 1st Moore .avi' 21 | 22 | 23 | 24 | fps = 1 # slik na sekundo 25 | 26 | start_frame = 3 # zaporedna številka začetnega okvirja 27 | stop_frame = 0 # zaporedna številka zadnjega okvirja 28 | frame_step = 1 29 | 30 | image_folder = 'C:/Users/akocjan/Desktop/'+mapa_animacija #PATH+mapa_animacija 31 | video_name = image_folder + ime_videa 32 | 33 | frame = cv2.imread(image_folder+koren_slike+str(start_frame)+'.png') 34 | height, width, layers = frame.shape 35 | 36 | #fourcc = cv2.VideoWriter_fourcc(*'XVID') 37 | #fourcc = cv2.VideoWriter_fourcc(*'MP4V') 38 | fourcc = cv2.VideoWriter_fourcc('M','J','P','G') 39 | 40 | video = cv2.VideoWriter(video_name, fourcc, fps, (width, height)) 41 | 42 | 43 | for snap in range(-start_frame, -stop_frame+1, frame_step): 44 | im=cv2.imread(image_folder+koren_slike+str(-snap)+'.png') 45 | #print(i, ' ', im.shape) 46 | '''.................................................................................................... these lines are used to shape all figures to same size .................................................''' 47 | #im=im[:,:670,:3] 48 | #cv2.imwrite(image_folder+'figure_'+str(i)+'.png', im) 49 | #print(i, ' ', im.shape) 50 | '''....................................................................................................................................................................................................................................''' 51 | video.write(im) 52 | 53 | cv2.destroyAllWindows() 54 | video.release() 55 | 56 | 57 | """ ........................................................ Reading the. AVI video .............................................""" 58 | """ 59 | import matplotlib.pyplot as plt 60 | plt.ion() 61 | 62 | # read video 63 | video_name = PATH+mapa_video+ime_videa 64 | cap = cv2.VideoCapture(video_name) 65 | 66 | while(cap.isOpened()): 67 | ret, frame = cap.read() 68 | #gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 69 | #plt.figure() 70 | cv2.imshow('frame', frame) 71 | 72 | if cv2.waitKey(1) & 0XFF == ord('q'): 73 | break 74 | 75 | cap.release() 76 | cap.destroyAllWindows() 77 | """ 78 | -------------------------------------------------------------------------------- /get_color.py: -------------------------------------------------------------------------------- 1 | from numpy.linalg import multi_dot 2 | import numpy as np 3 | import math 4 | import matplotlib.pyplot as plt 5 | from mpl_toolkits.mplot3d import Axes3D 6 | plt.ion() 7 | 8 | k=35.2643896827 9 | 10 | def get_color(x,y,z): 11 | u = z-x 12 | v = x-y 13 | w = y 14 | rgb = np.array([u,v,w]) 15 | RGB = 255*rgb/np.max(rgb) 16 | return RGB.astype('int') 17 | 18 | def random_xy_tilt(): 19 | x = np.random.uniform(0,1) 20 | y = np.random.uniform(0,x) 21 | return x,y 22 | 23 | def Rotate_the_Cube_XY(alpha, beta): 24 | global RmX, RmY 25 | cube = np.array([ 26 | [1, 0, 0], 27 | [0, 1, 0], 28 | [0, 0, 1] 29 | ]) 30 | 31 | RmY = np.array([ # rotation matrix around Y-axis 32 | [math.cos(math.radians(alpha)), 0, math.sin(math.radians(alpha))], 33 | [0, 1, 0], 34 | [-math.sin(math.radians(alpha)), 0, math.cos(math.radians(alpha))], 35 | ]) 36 | 37 | RmX = np.array([ # rotation matrix around X-axis 38 | [1, 0, 0], 39 | [0, math.cos(math.radians(beta)), math.sin(math.radians(beta))], 40 | [0, - math.sin(math.radians(beta)), math.cos(math.radians(beta))], 41 | ]) 42 | 43 | oix = multi_dot([cube, RmY, RmX]) 44 | 45 | return oix 46 | 47 | def Rotate_the_Cube_Z(xy_cube, gamma): 48 | RmZ = np.array([# rotation matrix around Z-axis 49 | [math.cos(math.radians(gamma)), math.sin(math.radians(gamma)), 0], 50 | [- math.sin(math.radians(gamma)), math.cos(math.radians(gamma)), 0], 51 | [0, 0, 1], 52 | ]) 53 | 54 | oiz = np.dot(xy_cube, RmZ) 55 | 56 | return oiz 57 | 58 | #++++++++++++++++++++++ exe line ++++++++++++++++++++++++++++++++++++++++ 59 | 60 | ''' tilting the cube ''' 61 | #x,y = random_xy_tilt() 62 | x,y = 1,0 63 | RGB = get_color(x,y,1) 64 | alfa = math.degrees(math.atan(x)) 65 | beta = math.degrees(math.atan(y))- 9.7356103173*y 66 | cub_xy = Rotate_the_Cube_XY(alfa, beta) 67 | gama = math.degrees(math.atan(np.random.uniform(0,1))) 68 | c = Rotate_the_Cube_Z(cub_xy, gama) 69 | 70 | 71 | ''' showing the tilted cube ''' 72 | 73 | ca = np.array([[0,0,0], c[0], c[1], c[2], c[0]+c[1], c[1]+c[2], c[0]+c[2], c[0]+c[1]+c[2]]) 74 | ogli = [(0,1), (0,2), (0,3), (1,4), (2,4), (2,5), (4,7), (1,6), (3,6), (3,5), (5,7), (6,7)] 75 | 76 | def edges(p,q): 77 | edge = [[ca[p][0], ca[q][0]], [ca[p][1], ca[q][1]], [ca[p][2], ca[q][2]]] 78 | return edge 79 | 80 | fig = plt.figure() 81 | ax = fig.add_subplot(111, projection='3d') 82 | 83 | '''------------- fake bounding box ----------------''' 84 | ax.set_aspect('equal') 85 | max_range = 2 86 | Xb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][0].flatten() 87 | Yb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][1].flatten() 88 | Zb = 0.5*max_range*np.mgrid[-1:2:2,-1:2:2,-1:2:2][2].flatten() 89 | for xb, yb, zb in zip(Xb, Yb, Zb): 90 | ax.plot([xb], [yb], [zb], 'w') 91 | ''' -----------------------------------------------------''' 92 | 93 | ax.scatter(ca[:,0], ca[:,1], ca[:,2], marker='o', s=80, color='blue') 94 | for i in ogli: 95 | rob = edges(i[0],i[1]) 96 | ax.plot(rob[0], rob[1], rob[2], color='red') 97 | 98 | ax.set_xlabel('X') 99 | ax.set_ylabel('Y') 100 | ax.set_zlabel('Z') 101 | 102 | 103 | ''' get the grain oriented color ''' 104 | slika=np.zeros((3,3,3)).astype('int') 105 | slika[1,1]=RGB 106 | plt.figure() 107 | plt.imshow(slika) 108 | 109 | 110 | #-------------------------------------------------------------------------------------------------------------------- 111 | ''' 112 | R=get_color(0,0,1) 113 | G=get_color(1,0,1) 114 | B=get_color(1,1,1) 115 | 116 | Y=get_color(0.5,0,1) 117 | P=get_color(0.5,0.5,1) 118 | T=get_color(1,0.5,1) 119 | ''' 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /fast_image_saver.py: -------------------------------------------------------------------------------- 1 | """++++++++++++++++++++++++++++ FAST creation of .png animation figures by multiprocessing +++++++++++++++++++++++++++++++++++++++++++++++""" 2 | import os 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | plt.ion() 6 | import matplotlib 7 | matplotlib.use('Agg') 8 | 9 | from mpl_toolkits.axes_grid1 import make_axes_locatable 10 | 11 | import multiprocessing 12 | import concurrent.futures 13 | 14 | first = 10 15 | last = 23 16 | picker = 1 17 | g= 9 18 | smer = 2 19 | 20 | PATH = 'C:/sm-2018-w64-0-3/WORK/cooling_plate_Files/' 21 | 22 | #mapa = PATH+'CA_1' # Folder name 23 | mapa = 'CA_4' 24 | flashies = 'flashies' 25 | #flashies = 'parallel_flashies' 26 | 27 | animation_figures = 'animation_figures_MP' 28 | 29 | cmap = 'jet' 30 | Tmelt = 1200 # Melting Point in degrees Celsius 31 | cell_size = 50 / 4 # FE cell size; unit: MICROMETER [um] 32 | time_step = 5e-05 / 8 # FE time step; unit: SECOND [s] 33 | 34 | 35 | 36 | # Get time matrix 37 | def Load_Time_Step(num): 38 | global micro, Z,Y,X, field 39 | """ Microstructure """ 40 | flash = flashies+'/flashy_snap_'+str(num)+'.npy' 41 | micro=np.load(mapa+'/'+flash) 42 | """ Temperature """ 43 | polje = 'salome_'+str(num)+'.npy' 44 | field_Kelvin=np.load(mapa+'/'+polje) 45 | #c=np.load(mapa+'/domain_constraints.npy') 46 | c=np.array([ 0, 10, 12, 52, 17, 155]) 47 | field_Kelvin = field_Kelvin[c[0]:c[1], c[2]:c[3], c[4]:c[5]] # Constrained temperature field in Kelvins 48 | field = field_Kelvin - 273 # Constrained temperature field in degrees Celsius 49 | Z=micro.shape[0] ; Y=micro.shape[1]; X=micro.shape[2] # Domain (microstructure, phase and 50 | 51 | def fast_image_saver(im_counter, depth, axis): 52 | Load_Time_Step(im_counter) 53 | fig, axs = plt.subplots(nrows=3, sharex=True, sharey=False, figsize=(5,8)) 54 | axs[0].set_title('microstructure (grain orientation-colored)', fontsize=11) 55 | phase=np.full(micro.shape, (255, 255, 153)) 56 | phase[field<=Tmelt]=(92, 92, 138) 57 | e=np.zeros((phase.shape[0],phase.shape[1],phase.shape[2],)) 58 | p=phase[:,:,:,0] 59 | e[p==92]=0; e[p==255]=1 60 | 61 | if axis == 2: # Z_cut 62 | plt.ylabel('X'); plt.xlabel('Y') 63 | fig.suptitle('Projekcija v smeri Z, {0}% od začetka domene, TIME: {1} msec. (step # {2})'.format(round((depth+1)*100/Z, 1), "%6.3f" % (round(im_counter*time_step*1000, 3)), im_counter), fontsize=14) 64 | axs[0].imshow(micro[depth,:,:], cmap=cmap) 65 | axs[1].imshow(phase[depth,:,:], cmap=cmap) 66 | x_dim=np.max(np.sum(e[depth,:,:],axis=0))*cell_size ; y_dim=np.max(np.sum(e[depth,:,:],axis=1) )*cell_size 67 | temp=field[depth,:,:] 68 | 69 | try: 70 | plt.savefig(mapa+'/'+animation_figures+'/figure_'+str(im_counter)+'.png', bbox_inches='tight') 71 | except FileNotFoundError: 72 | os.mkdir(mapa+'/'+animation_figures) 73 | plt.savefig(mapa+'/'+animation_figures+'/figure_'+str(im_counter)+'.png', bbox_inches='tight') 74 | 75 | return im_counter 76 | 77 | 78 | if __name__ == '__main__': 79 | 80 | with concurrent.futures.ThreadPoolExecutor() as executor: 81 | rezultati = [] 82 | for slika in range(first,last,picker): 83 | rezultati.append(executor.submit(fast_image_saver, slika, g, smer)) 84 | #fast_image_saver(slika, g, smer) 85 | 86 | out=[i.result()for i in rezultati] 87 | 88 | 89 | """-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------""" 90 | -------------------------------------------------------------------------------- /MPI_pool_toycode.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Pool 2 | from functools import partial 3 | import itertools 4 | from inspect import signature 5 | import numpy as np 6 | import time 7 | 8 | # to obtain arguments of callable: 9 | # signature(p).parameters # where p is callable 10 | 11 | 12 | H=np.full((3,100,100,),1) 13 | G=np.full((3,100,100,),2) 14 | counter=0 15 | 16 | def g_pool(y): 17 | global H,G, counter 18 | H=(H+y[0]) 19 | G=(y[1]+H) 20 | counter+=1 21 | return H,G 22 | 23 | def g_exe(Y, H, G): 24 | global counter 25 | for y in Y: 26 | H=(H+y[0]) 27 | G=(y[1]+H) 28 | counter+=1 29 | return H,G 30 | 31 | 32 | a = range(1,1000) 33 | b = range(1,1000) 34 | 35 | c = list(itertools.product(a, b)) # it replaces double (nested) for loops, i.e. for i in a: for j in b 36 | 37 | 38 | SINGLE_executor = False # CPU: 39.4 s | H[0,0,0] = 499000501 | G[0,0,0] = 499001500 | counter = 998001 39 | SINGLE_pool = False # CPU: 40.7 s | H[0,0,0] = 499000501 | G[0,0,0] = 499001500 | counter = 998001 40 | 41 | TPE = False # CPU: 39.4 s | H[0,0,0] = 499000501 | G[0,0,0] = 499001500 | counter = 998001 42 | POOL = True 43 | 44 | 45 | 46 | if SINGLE_executor: 47 | start = time.time() 48 | #----------------------------------------------------------------------------------------------- process 49 | H,G = g_exe(c, H, G) 50 | #---------------------------------------------------------------------------------------------------------- 51 | end = time.time() 52 | print('Single executor process FINISHED in ', round(end-start, 1), ' seconds.') 53 | print('H[0,0,0] = ', H[0,0,0]) 54 | print('G[0,0,0] = ', G[0,0,0]) 55 | print('counter = ',counter) 56 | 57 | 58 | if SINGLE_pool: 59 | start = time.time() 60 | #----------------------------------------------------------------------------------------------- process 61 | #L=[] 62 | for i in c: 63 | H,G = g_pool(i) 64 | #L.append((H,G)) 65 | #---------------------------------------------------------------------------------------------------------- 66 | end = time.time() 67 | print('Single pool process FINISHED in ', round(end-start, 1), ' seconds.') 68 | print('H[0,0,0] = ', H[0,0,0]) 69 | print('G[0,0,0] = ', G[0,0,0]) 70 | print('counter = ',counter) 71 | 72 | 73 | if True:#POOL: 74 | start = time.time() 75 | #----------------------------------------------------------------------------------------------- process 76 | if __name__ == '__main__': 77 | pool = Pool() 78 | #basic_partial = partial( basic, H,G) 79 | #w=pool.map(basic_partial, c) 80 | 81 | #g_part = partial(g, HH, GG) 82 | #w=pool.map(g_part, c) 83 | print('bua bana') 84 | w=pool.map(g_pool, c) 85 | pool.close() 86 | pool.join() 87 | #---------------------------------------------------------------------------------------------------------- 88 | end = time.time() 89 | print('Pool process FINISHED in ', round(end-start, 1), ' seconds.') 90 | #print('H[0,0,0] = ', w[0][0][0,0,0]) 91 | #print('G[0,0,0] = ', w[0][1][0,0,0]) 92 | print('counter = ',counter) 93 | 94 | 95 | 96 | if TPE: 97 | import multiprocessing 98 | import concurrent.futures 99 | start = time.time() 100 | #----------------------------------------------------------------------------------------------- process 101 | if __name__ == '__main__': 102 | with concurrent.futures.ThreadPoolExecutor() as executor: 103 | r=[] 104 | r.append(executor.submit(g_exe, c, H, G)) 105 | 106 | q=[i.result() for i in r] 107 | #---------------------------------------------------------------------------------------------------------- 108 | end = time.time() 109 | print('ThreadPoolExecutor process FINISHED in ', round(end-start, 1), ' seconds.') 110 | print('H[0,0,0] = ', q[0][0][0,0,0]) 111 | print('G[0,0,0] = ', q[0][1][0,0,0]) 112 | print('counter = ',counter) 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /override_CA_long_track_backup.py: -------------------------------------------------------------------------------- 1 | import json 2 | import numpy as np 3 | from numpy.linalg import multi_dot 4 | import random, math, time 5 | import matplotlib.pyplot as plt 6 | plt.ion() 7 | 8 | # **** Grain orientation and Cube Rotation Matrices **** 9 | 10 | def Rotate_the_Cube_XY(alpha, beta): # rotation of cube around Y- axis (alpha angle) and X-axis (beta angle) 11 | global RmX, RmY 12 | cube = np.array([ 13 | [1, 0, 0], 14 | [0, 1, 0], 15 | [0, 0, 1] 16 | ]) 17 | RmY = np.array([ # rotation matrix around Y-axis 18 | [math.cos(math.radians(alpha)), 0, math.sin(math.radians(alpha))], 19 | [0, 1, 0], 20 | [-math.sin(math.radians(alpha)), 0, math.cos(math.radians(alpha))], 21 | ]) 22 | RmX = np.array([ # rotation matrix around X-axis 23 | [1, 0, 0], 24 | [0, math.cos(math.radians(beta)), math.sin(math.radians(beta))], 25 | [0, - math.sin(math.radians(beta)), math.cos(math.radians(beta))], 26 | ]) 27 | oix = multi_dot([cube, RmY, RmX]) 28 | return oix 29 | 30 | def Rotate_the_Cube_Z(xy_cube, gamma): # rotation of cube around Z- axis (gamma angle) 31 | RmZ = np.array([# rotation matrix around Z-axis 32 | [math.cos(math.radians(gamma)), math.sin(math.radians(gamma)), 0], 33 | [- math.sin(math.radians(gamma)), math.cos(math.radians(gamma)), 0], 34 | [0, 0, 1], 35 | ]) 36 | oiz = np.dot(xy_cube, RmZ) 37 | oiz_switched_rows_and_columns = oiz[np.ix_([2,0,1], [2,0,1])] 38 | return oiz_switched_rows_and_columns 39 | 40 | def get_color(x,y): 41 | u = 1-x 42 | v = x-y 43 | w = y 44 | rgb = np.array([u,v,w]) 45 | RGB = 255*rgb/np.max(rgb) 46 | return RGB.astype('int') 47 | 48 | def random_xy_tilt(posibilities): 49 | xran = np.random.randint(0, posibilities+1) 50 | x = xran / posibilities 51 | y = np.random.randint(0, xran+1)/posibilities 52 | return x,y 53 | 54 | rp = 90 55 | 56 | Z=1 57 | X=96 58 | Y=128 59 | 60 | case = 'SLM_2D_Source' ; subcase = '0002' 61 | PATH = 'C:/sm-2018-w64-0-3/WORK/'+case+'_Files/post processing database/'+subcase+'/' 62 | 63 | mapa = 'INTER time=40, space=8 Z[7-8], X[15-27], Y[12-97], 1500°C, N=12/' 64 | 65 | cut_BOTTOM = 'flashies_faza' ; cut_UP = '' 66 | 67 | X_cutoff_percent = 75 ; X_cutoff = int(X_cutoff_percent * X / 100) # Analogy with Hatch Spacing 68 | 69 | yp_count = 0 70 | cutoff_limit = 64 71 | 72 | FS_left = np.load(PATH+mapa+cut_BOTTOM+'/results/cut_'+str(yp_count) +'.npy')[:,:X_cutoff,:] # FS stands for "flashy snap" 73 | FS_right = np.load(PATH+mapa+cut_BOTTOM+'/results/cut_'+str(yp_count+1)+'.npy')[:,:X_cutoff,:cutoff_limit] 74 | FS = np.dstack((FS_left, FS_right)) 75 | grain_ID = list(np.unique(FS).astype('int')); grain_ID.remove(0) 76 | 77 | HA = np.zeros((Z,X-X_cutoff, Y)) 78 | 79 | faza = np.hstack((HA,FS)) 80 | 81 | 82 | 83 | ''' Construction of arbitrary asc dictionary (asc_arb) --- in real process, for each item in grain_ID data from nuclei_data.json will be imported to form new asc ''' 84 | 85 | asc_arb = {} 86 | for j in grain_ID: 87 | """ generation of random grain orientation """ 88 | x,y = random_xy_tilt(rp) 89 | rgb = get_color(x,y) 90 | alfa = math.degrees(math.atan(x))- 9.7356103173*x*y 91 | beta = math.degrees(math.atan(y))- 9.7356103173*x*y 92 | cub_xy = Rotate_the_Cube_XY(alfa, beta) 93 | gama = math.degrees(math.atan(np.random.randint(0, rp+1)/rp)) 94 | oi = Rotate_the_Cube_Z(cub_xy, gama) 95 | asc_arb[j] ={'oi': oi, 'alfa':alfa, 'beta':beta, 'gama':gama, 'rgb':rgb, } # ALL data about nuclei 96 | 97 | 98 | with open(PATH+mapa+'nuclei_data.json', 'w') as nuks: # Writing data of ALL nuclei as .json file, but values must be list NOT np.array !!! 99 | asc_list =asc_arb.copy() 100 | for nuk in asc_list: 101 | asc_list[nuk]['oi']=asc_arb[nuk]['oi'].tolist() 102 | asc_list[nuk]['rgb']=asc_arb[nuk]['rgb'].tolist() 103 | asc_list = {str(keyy): vall for keyy, vall in asc_list.items()} 104 | json.dump(asc_list, nuks) 105 | 106 | 107 | ''' Loading asc from nuclei_data.json''' 108 | with open(PATH+mapa+'nuclei_data.json', 'r') as nuks: 109 | asc = json.load(nuks) 110 | asc = {int(keyy): vall for keyy, vall in asc.items()} 111 | for nuk in asc: 112 | asc[nuk]['oi']=np.array(asc[nuk]['oi']) 113 | asc[nuk]['rgb']=np.array(asc[nuk]['rgb']) 114 | 115 | 116 | plt.imshow(faza[0]) 117 | -------------------------------------------------------------------------------- /nova_paralelizacija.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Pool, Process, freeze_support, set_start_method 2 | from functools import partial 3 | import itertools 4 | import time 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | import os 8 | plt.ion() 9 | def merging(prva,druga): 10 | tot = np.where(druga==0, prva, druga) 11 | return tot 12 | def GG_(attr3, attr2): # attr3= faza, attr2= Selection 13 | grain=attr2[0];s=attr2[1] 14 | ''' ----------------------------------------- GROUP 1 ::: [001], [010] >>> 4 sites -------------------------------------------''' 15 | if s == '001': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(0,0), (1,0)), 'constant')[:,:,:-1]==grain) , grain, attr3) 16 | elif s == '00_1': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(0,0), (0,1)), 'constant')[:,:,1:]==grain), grain, attr3) 17 | elif s == '010': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(1,0), (0,0)), 'constant')[:,:-1,:]==grain), grain, attr3) 18 | elif s == '0_10': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(0,1), (0,0)), 'constant')[:,1:,:]==grain), grain, attr3) 19 | return attr3 20 | 21 | 22 | from multiprocessing import sharedctypes 23 | 24 | Z,X,Y = 1, 1001, 1001 25 | faza = np.zeros((Z,X,Y)) 26 | 27 | #faza0 = np.ctypeslib.as_ctypes(np.zeros((Z,X,Y))) 28 | #faza1 = sharedctypes.Array(faza0._type_, faza0, lock=True) 29 | #faza1 = sharedctypes.copy(faza0) 30 | #faza = np.ctypeslib.as_array(faza1) 31 | 32 | 33 | M = { 1: {'ß':(0, 500, 500)}, 34 | 2: {'ß':(0, 800, 500)}, 35 | 3: {'ß':(0, 350, 300)}, 36 | 4: {'ß':(0, 200, 100)}, 37 | 5: {'ß':(0, 750, 750)}, 38 | } 39 | for i in M: 40 | faza[M[i]['ß'][0],M[i]['ß'][1],M[i]['ß'][2]]=i 41 | 42 | grain_ID = np.array([1,2,3,4,5]) 43 | smeri=np.array(['001', '00_1', '010', '0_10']) 44 | Selection = list((itertools.product(grain_ID, smeri))) 45 | 46 | 47 | def single_core(): 48 | global faza 49 | single_start = time.time() 50 | for i in range(20): 51 | for j in Selection: 52 | faza=GG_(faza,j) 53 | single_stop = time.time() 54 | print('Single Core computing time = ', int(single_stop-single_start)) 55 | 56 | 57 | def MPI_Pool(): 58 | mpi_start = time.time() 59 | os.system("taskset -p 0xff %d" % os.getpid()) 60 | #freeze_support() 61 | #set_start_method('spawn') 62 | pool = Pool() 63 | for i in range(20): 64 | od=0; do=16 65 | for j in range(int(len(Selection)/16)): 66 | 67 | cpu_list = pool.map(partial(GG_, faza), Selection[od:do]) 68 | 69 | ''' 70 | total=merging(cpu_list[0], cpu_list[1]) 71 | if len(cpu_list)> 2: 72 | for move in range(2, len(cpu_list)): 73 | total=merging(total, cpu_list[move]) 74 | faza = total.copy() 75 | od+=16; do+=16 76 | ''' 77 | pool.close() 78 | pool.join() 79 | 80 | mpi_stop = time.time() 81 | print('MPI computing time = ', int(mpi_stop-mpi_start)) 82 | 83 | 84 | def MPI_Process(): 85 | mpi_start = time.time() 86 | freeze_support() 87 | for i in range(2): 88 | procesi=[] 89 | for j in Selection: 90 | p = Process(target=GG_, args=[faza,j]) 91 | p.start() 92 | procesi.append(p) 93 | 94 | for q in procesi: 95 | q.join() 96 | 97 | 98 | import concurrent.futures 99 | 100 | def MPI_Concurrent_Futures(): 101 | global faza 102 | mpi_start = time.time() 103 | ''' 104 | with concurrent.futures.ThreadPoolExecutor() as executor: 105 | for i in range(20): 106 | for j in Selection[:]: 107 | results=[] 108 | results.append(executor.submit(partial(GG_, faza),j)) 109 | faza=results[0].result() 110 | ''' 111 | with concurrent.futures.ProcessPoolExecutor() as executor: 112 | Q=partial(GG_, faza) 113 | for i in range(20): 114 | for j, faza in zip(Selection[:], executor.map(Q, Selection[:])): 115 | Q=partial(GG_, faza) 116 | 117 | 118 | ''' 119 | #for i in range(1): 120 | #for j, faza in zip(range(int(len(Selection))), executor.map(partial(GG_, faza), Selection) ): 121 | #print(j) 122 | #executor.map(partial(GG_, faza), Selection) 123 | 124 | 125 | total=merging(cpu_list[0], cpu_list[1]) 126 | if len(cpu_list)> 2: 127 | for move in range(2, len(cpu_list)): 128 | total=merging(total, cpu_list[move]) 129 | faza = total.copy() 130 | od+=16; do+=16 131 | ''' 132 | mpi_stop = time.time() 133 | print('MPI computing time = ', int(mpi_stop-mpi_start)) 134 | 135 | 136 | 137 | if __name__ == '__main__': 138 | #single_core() 139 | MPI_Concurrent_Futures() 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | ''' 151 | # The tutorial from StackOverFlow, how Python for loop is paralelized 152 | # setup output lists 153 | output1 = list() 154 | output2 = list() 155 | output3 = list() 156 | 157 | for j in range(0, 10): 158 | # calc individual parameter value 159 | parameter = j * offset 160 | # call the calculation 161 | out1, out2, out3 = calc_stuff(parameter = parameter) 162 | 163 | # put results into correct output list 164 | output1.append(out1) 165 | output2.append(out2) 166 | output3.append(out3) 167 | 168 | 169 | pool = multiprocessing.Pool(4) 170 | out1, out2, out3 = zip(*pool.map(calc_stuff, range(0, 10 * offset, offset))) 171 | ''' 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /matrix_interpolation_toycode.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | from scipy.ndimage.interpolation import map_coordinates 4 | import matplotlib.pyplot as plt 5 | import matplotlib.animation as animation 6 | import random, math, time 7 | plt.ion() 8 | 9 | # FE analysis result from SALOME 10 | #PATH = 'C:/sm-2018-w64-0-3/WORK/kode za Salome/Cellular Automata/3D_ss800_f5R8c4f8b23d2N30_10W_t5/' 11 | PATH = 'C:/sm-2018-w64-0-3/WORK/kode za Salome/Cellular Automata/matrix_interpolation_toycode/' 12 | #file = '3D_ss800_f5R8c4f8b23d2N30_10W_t5.npy' # .npy filename with FE analysis results (after meshio_postprocessing.py) 13 | mapa = 'CA_1_1' # Folder name 14 | #Matrix_4D = np.load(PATH+file) 15 | 16 | 17 | Matrix_4D = np.zeros((6,3,3,3)); m_values = [1 ,6, 11, 16, 21, 26] 18 | for i in range(6): 19 | Matrix_4D[i] = m_values[i] 20 | 21 | 22 | ''' ****************************************************************************************************************************************''' 23 | 24 | FEM_time_factor = 1 25 | scale_up = 2 26 | increase_tuple = (FEM_time_factor * scale_up, scale_up, scale_up, scale_up) # resolution increase factor by linear interpolation 27 | ''' ****************************************************************************************************************************************''' 28 | 29 | time_range = (1, Matrix_4D.shape[0]-1) 30 | #time_range = (0,31) 31 | 32 | auto_reduce_domain_size = False 33 | Tmelt_Celsius = 1000 - 273 # Melting point; unit: degrees C [deg. C] - for domain size reduction 34 | Tmelt= Tmelt_Celsius + 273 # Melting point; unit: KELVIN [K] 35 | 36 | ''' domain limits ----> reduction of FE domain to size a bit larger than the molten track, where the crystallization occurs .. ''' 37 | 38 | def Domain_Size_Reduction(domain, threshold): 39 | global z_min, z_max, x_min, x_max, y_min, y_max 40 | ax2=np.where(np.any(domain > threshold, axis=2)) 41 | ax1=np.where(np.any(domain > threshold, axis=1)) 42 | z_min = np.min(ax2[0]); z_max = np.max(ax2[0])+1 43 | x_min = np.min(ax2[1]); x_max = np.max(ax2[1])+1 44 | y_min = np.min(ax1[1]); y_max = np.max(ax1[1])+1 45 | 46 | reduced_domain = domain[z_min:z_max, x_min:x_max, y_min:y_max] 47 | return reduced_domain 48 | 49 | 50 | if auto_reduce_domain_size: 51 | limits = [ [], [], [], [], [], [] ] 52 | for i in time_range: 53 | Domain_Size_Reduction(Matrix_4D[i], Tmelt) 54 | limits[0].append(z_min); limits[1].append(z_max) 55 | limits[2].append(x_min); limits[3].append(x_max) 56 | limits[4].append(y_min); limits[5].append(y_max) 57 | 58 | z_min, z_max, x_min, x_max, y_min, y_max = min(limits[0]), max(limits[1]), min(limits[2]), max(limits[3]), min(limits[4]), max(limits[5]) 59 | 60 | else: 61 | z_min = None #3 62 | z_max = None #9 63 | 64 | x_min = None #13 65 | x_max = None #27 66 | 67 | y_min = None #10 68 | y_max = None #50 69 | 70 | mat_4d = Matrix_4D[:, z_min:z_max, x_min:x_max, y_min:y_max] # Reduced 4D matrix 71 | 72 | def f(x, tresh): 73 | T = np.load(PATH+mapa+'/salome_'+str(x)+'.npy') 74 | P = np.zeros(T.shape) 75 | P[T >(tresh+273)]=1 76 | return T, P 77 | 78 | def Matrix_Interpolation(A, it): 79 | if auto_reduce_domain_size: 80 | B_tuple = (it[0], (z_max-z_min)*it[1], (x_max-x_min)*it[2], (y_max-y_min)*it[3]) 81 | else: 82 | B_tuple = (A.shape[0]*it[0], A.shape[1]*it[1], A.shape[2]*it[2], A.shape[3]*it[3]) 83 | new_dims = [] 84 | for original_length, new_length in zip(A.shape, B_tuple): 85 | new_dims.append(np.linspace(0, original_length-1, new_length)) 86 | 87 | coords = np.meshgrid(*new_dims, indexing='ij') 88 | B = map_coordinates(A, coords, order=1) 89 | return B 90 | 91 | 92 | '''....................... toycode .......................................................................................... ''' 93 | 94 | a=np.array([0,1]).astype('float') 95 | #a=np.arange(2).astype('float') 96 | IT = (100,) 97 | 98 | def toy_matrix_interpolation(A, it): 99 | global B_tuple, new_dims, coords, original_length, new_length 100 | B_tuple = (A.shape[0]*it[0], ) 101 | new_dims = [] 102 | for original_length, new_length in zip(A.shape, B_tuple): 103 | new_dims.append(np.linspace(0, original_length-1, int(new_length))) 104 | coords = np.meshgrid(*new_dims, indexing='ij') 105 | B = map_coordinates(A, coords, order=1) 106 | return B 107 | 108 | b=toy_matrix_interpolation(a, IT); print(np.around(b,2)) 109 | 110 | plt.plot(a,marker='s', color='grey'); plt.title('original') 111 | 112 | plt.figure();plt.title('Interpolated') 113 | plt.plot(b,marker='s', color='magenta') 114 | 115 | ''' ................................................................................................................................... ''' 116 | 117 | 118 | __name__='comment this line, if you want to execute matrix_interpolation' 119 | if __name__=='__main__': 120 | 121 | counter = time_range[0]*FEM_time_factor-1 122 | start_total = time.time() 123 | 124 | 125 | for n in range(time_range[0], time_range[1] + 1): 126 | print(35*'~') 127 | print('Processing time step ',n,'/',time_range[1]+1,' ..') 128 | start = time.time() 129 | inp_mat = mat_4d[n:n+3] 130 | out_mat = Matrix_Interpolation(inp_mat,increase_tuple) 131 | del inp_mat 132 | for i in out_mat: 133 | counter+=1 134 | try: 135 | np.save(PATH+mapa+'/'+'salome_'+str(counter)+'.npy', i) 136 | except FileNotFoundError: 137 | os.mkdir(PATH+mapa) 138 | np.save(PATH+mapa+'/'+'salome_'+str(counter)+'.npy', i) 139 | end = time.time() 140 | print('Computing time: ',round(end-start, 3),' sec.') 141 | print(35*'~'); print() 142 | 143 | print('Total computing time = ',round(time.time()-start_total, 3),' seconds.') 144 | 145 | 146 | ''' ............................ checking the results ............................... ''' 147 | 148 | ''' 149 | u=[i for i in range(time_range[0], time_range[1]+1)] 150 | 151 | maxi = np.where(np.max(mat_4d)== mat_4d) 152 | 153 | plt.plot(u,mat_4d[time_range[0]:time_range[1]+1, maxi[1][0], maxi[2][0], maxi[3][0],], marker='s', color='green',) 154 | 155 | 156 | plt.figure() 157 | v=[]; w=[] 158 | for i in range(0, 11): 159 | w.append(i) 160 | q=np.load(PATH+mapa+'/salome_'+str(i)+'.npy') 161 | v.append(q[maxi[1][0], maxi[2][0], maxi[3][0],]) 162 | 163 | plt.plot(w,v, marker='o', color='red') 164 | ''' 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /orientation_weight_coefficient.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math 3 | import matplotlib.pyplot as plt 4 | from numpy.linalg import multi_dot 5 | plt.ion() 6 | 7 | 8 | Oi001 = np.array([ 9 | [1, 0, 0], 10 | [0, 1, 0], 11 | [0, 0, 1] 12 | ]) 13 | 14 | Oi101 = np.array([ 15 | [math.cos(math.radians(45)), 0, math.cos(math.radians(45))], 16 | [0, 1, 0], 17 | [-math.cos(math.radians(45)), 0, math.cos(math.radians(45))], 18 | ]) 19 | 20 | k=35.2643896827 21 | 22 | Oi111 = np.array([ 23 | [math.cos(math.radians(k))* math.cos(math.radians(30)), - math.cos(math.radians(k))* math.cos(math.radians(60)), math.cos(math.radians(90-k))], 24 | [0, math.cos(math.radians(k)), math.cos(math.radians(90-k))], 25 | [- math.cos(math.radians(k))* math.cos(math.radians(30)), -math.cos(math.radians(k))* math.cos(math.radians(60)), math.cos(math.radians(90-k))], 26 | ]) 27 | 28 | '''--------------------------------------------------------------------------------------------------------------------------------- funkcije --------------------------------------------------------------''' 29 | def Get_001_101_111_vectors(m, axis): 30 | global red, green, blue 31 | ax = {'x':0, 'y':1, 'z':2} 32 | Qi = np.array([ 33 | m[2], 34 | np.array([m[0,0]+m[2,0], m[0,1]+m[2,1], m[0,2]+m[2,2]]), 35 | np.array([m[0,0]+m[1,0]+m[2,0], m[0,1]+m[1,1]+m[2,1], m[0,2]+m[1,2]+m[2,2]]), 36 | ]) 37 | Qi = np.around(Qi, decimals=4) 38 | Qi_lengths = np.linalg.norm(Qi, axis=1) 39 | Qi_axed = Qi[:,ax[axis]] 40 | 41 | R_vector = np.sum(Qi, axis=0); print('R_vector is: ', R_vector) 42 | 43 | return Qi, Qi_lengths, R_vector 44 | 45 | 46 | def Get_Vector_Sum(m): 47 | sum_m = np.array([m[0,0]+m[1,0]+m[2,0], m[0,1]+m[1,1]+m[2,1], m[0,2]+m[1,2]+m[2,2]]) 48 | return sum_m 49 | 50 | def Get_Projection_Height(v1, v2): 51 | ph = np.dot(v1,v2) 52 | return ph 53 | 54 | 55 | def Get_Vector_Angle(v1, v2, acute): 56 | # v1 is first vector 57 | # v2 is second vector 58 | angle_rad = np.arccos(np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))) # angle between vectors v1 and v2 in radians! 59 | angle = np.degrees(angle_rad) 60 | if (acute == True): 61 | return np.around(angle, decimals=2) 62 | else: 63 | return np.around(2 * np.pi - angle, decimals=2) 64 | 65 | 66 | def Rotate_the_Cube(alpha, beta): 67 | global RmX, RmY 68 | cube = np.array([ 69 | [1, 0, 0], 70 | [0, 1, 0], 71 | [0, 0, 1] 72 | ]) 73 | 74 | RmY = np.array([ # rotation matrix around Y-axis 75 | [math.cos(math.radians(alpha)), 0, math.sin(math.radians(alpha))], 76 | [0, 1, 0], 77 | [-math.sin(math.radians(alpha)), 0, math.cos(math.radians(alpha))], 78 | ]) 79 | 80 | RmX = np.array([ # rotation matrix around X-axis 81 | [1, 0, 0], 82 | [0, math.cos(math.radians(beta)), math.sin(math.radians(beta))], 83 | [0, - math.sin(math.radians(beta)), math.cos(math.radians(beta))], 84 | ]) 85 | 86 | oix = multi_dot([cube, RmY, RmX]) 87 | 88 | return oix 89 | 90 | 91 | def Custom_Grain(alpha,beta): 92 | global Oicus, Qicus 93 | Oicus = Rotate_the_Cube(alpha,beta) 94 | Qicus = Get_001_101_111_vectors(Oicus, 'z') 95 | koticus=[]; phcus = []; rvcus = Qicus[2] 96 | for i in range(3): 97 | koticus.append(Get_Vector_Angle(os_opazovanja, Qicus[0][i], True) ) 98 | phcus.append(Get_Projection_Height(os_opazovanja, Qicus[0][i])) 99 | 100 | return np.array(phcus) 101 | 102 | 103 | 104 | '''----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------''' 105 | 106 | os_opazovanja = np.array([0,0,1]) 107 | 108 | Qi001 = Get_001_101_111_vectors(Oi001,'z') 109 | Qi101 = Get_001_101_111_vectors(Oi101, 'z') 110 | Qi111 = Get_001_101_111_vectors(Oi111, 'z') 111 | 112 | koti001=[]; koti101=[]; koti111=[] 113 | ph001 = []; ph101=[]; ph111=[] 114 | rv001 = Qi001[2]; rv101 = Qi101[2]; rv111 = Qi111[2]; 115 | 116 | for i in range(3): 117 | koti001.append(Get_Vector_Angle(os_opazovanja, Qi001[0][i], True) ) 118 | koti101.append(Get_Vector_Angle(os_opazovanja, Qi101[0][i], True) ) 119 | koti111.append(Get_Vector_Angle(os_opazovanja, Qi111[0][i], True) ) 120 | 121 | ph001.append(Get_Projection_Height(os_opazovanja, Qi001[0][i])) 122 | ph101.append(Get_Projection_Height(os_opazovanja, Qi101[0][i])) 123 | ph111.append(Get_Projection_Height(os_opazovanja, Qi111[0][i])) 124 | 125 | 126 | 127 | P = np.transpose(np.array([np.array(ph001), np.array(ph101), np.array(ph111)])) 128 | #P = np.transpose(np.array([np.array(rv001), np.array(rv101), np.array(rv111)])) 129 | 130 | ''' ~~~~~~~~~~~~~~~~~~~ custom crystal orientation ~~~~~~~~~~~~~~~~~~~~~ ''' 131 | 132 | alfas = [22.5] #range(0,50,5) 133 | betas = [0] #range(0,36) 134 | 135 | asc = {} 136 | grain_counter=0 137 | 138 | R,G,B = [], [], [] 139 | all_counter=0; poz_counter=0 140 | for i in alfas: 141 | for j in betas: 142 | grain_counter+=1 143 | asc[grain_counter] ={ 'oi': Rotate_the_Cube(i,j), 'alpha':i, 'beta':j,} 144 | C = Custom_Grain(i,j) 145 | RGB = np.linalg.solve(np.array([P[0], P[1], P[2]]), C) 146 | if np.all(RGB>=0): 147 | #print(RGB) 148 | #print(i,j); print() 149 | poz_counter+=1 150 | R.append(RGB[0]); G.append(RGB[1]); B.append(RGB[2]) 151 | all_counter+=1 152 | 153 | #plt.plot(R, color='#ff0000', marker='o') 154 | #plt.plot(G, color='#00ff00', marker='o') 155 | #plt.plot(B, color='#0000ff', marker='o') 156 | 157 | 158 | slika=np.zeros((3,3,3)).astype('int') 159 | rgb = np.around(255*RGB, decimals=0) 160 | slika[1,1]=rgb 161 | plt.figure() 162 | plt.imshow(slika) 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | """ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ """ 181 | ''' 182 | x_orient = ['001', '101', '111'] 183 | 184 | plt.plot(x_orient, ph001, label='RED --- Oi001',marker='s', color='#ff0000'); #print(koti001) 185 | plt.plot(x_orient, ph101, label='GREEN --- Oi101',marker='^', color='#00ff00'); #print(koti101) 186 | plt.plot(x_orient, ph111, label='BLUE --- Oi111',marker='o', color='#0000ff'); #print(koti111) 187 | 188 | plt.plot(x_orient, phcus, label='custom',marker='.', color='magenta'); #print(koticus) 189 | 190 | plt.legend() 191 | 192 | 193 | K = np.array([np.array(koti001), np.array(koti101), np.array(koti111), np.array(koticus)]) 194 | K_delta = np.array([ 195 | np.absolute(K[:3,0]-K[3,0]), 196 | np.absolute(K[:3,1]-K[3,1]), 197 | np.absolute(K[:3,2]-K[3,2]), 198 | ]) 199 | ''' 200 | 201 | """-------------------------------------- ListedColormap for Coloring grains according to orientation --------------------------------------------------""" 202 | """ 203 | from matplotlib import cm 204 | from matplotlib.colors import ListedColormap 205 | 206 | viridis = cm.get_cmap('viridis', 5) 207 | newcolors = viridis(np.linspace(0, 1, 5)) 208 | 209 | slika = np.zeros((20,20)) 210 | 211 | slika[15,15]=1 212 | slika[5,5]=2 213 | slika[15,7]=3 214 | slika[10,10]=4 215 | 216 | 217 | asc = {1: {'rgb': (51, 204, 255), 'name': 'pastel_blue', 'hex': '#33ccff'}, 218 | 2: {'rgb': (204, 153, 255), 'name': 'pastel_purple', 'hex': '#cc99ff'}, 219 | 3: {'rgb': (255, 204, 153), 'name': 'pastel_orange', 'hex': '#ffcc99'}, 220 | 4: {'rgb': (153, 255, 153), 'name': 'pastel_green', 'hex': '#99ff99'}, 221 | } 222 | 223 | stevc = 1 224 | for grain in asc: 225 | c = asc[grain]['rgb'] 226 | color = np.array([c[0]/255, c[1]/255, c[2]/255, 1]) 227 | newcolors[stevc, :] = color 228 | stevc+=1 229 | 230 | newcmap = ListedColormap(newcolors) 231 | plt.imshow(slika, cmap=newcmap) 232 | """ 233 | 234 | 235 | 236 | 237 | 238 | -------------------------------------------------------------------------------- /combine_pictures.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy as np 3 | from PIL import Image 4 | import matplotlib.pyplot as plt 5 | plt.ion() 6 | 7 | case = 'SLM_2D_Source' ; subcase = '0002' 8 | 9 | #mapa = 'INTER time=40, space=8 Z[7-8], X[15-27], Y[12-97], 1500°C, N=12/' 10 | mapa = 'INTER time=1, space=8 Z[0-9], X[15-27], Y[12-97], 1500°C, N=12/' 11 | 12 | 13 | track = '2D 1st order Moore, real field/' # for zipping False only (combining cut figures of individual track..) 14 | #track = '3D 2nd order Moore (2 segments)/' 15 | 16 | '''**********************''' 17 | zipping = False 18 | '''**********************''' 19 | 20 | RGB_mode = True 21 | bessel = True 22 | 23 | perspektiva = 'Z' ; plast_range = (0,8) 24 | cut_range = (0,2) 25 | 26 | cutoff_limit = 64 27 | 28 | cell = 0.625 # pixel (cell) size in micrometers (for marker in microstructure figure) 29 | marker_size = 10 # marker size in micrometers (to calculate number of pixels in the marker) 30 | 31 | X = 96 32 | 33 | cuts_RGB = track+'cuts_RGB/' # folder 34 | cuts_faza = track+'cuts_faza/' 35 | 36 | cut_file_RGB = 'cut_RGB_' # fileroot 37 | cut_file_faza = 'cut_faza_' 38 | 39 | PATH = 'C:/sm-2018-w64-0-3/WORK/'+case+'_Files/post processing database/'+subcase+'/' 40 | 41 | # Cuts pictures to be without edges. How cool is that! :) 42 | def Cut_Pictures(folder, fileroot, perspective, layer): 43 | global names 44 | names = [fileroot+'{}'.format(i) for i in range (cut_range[0], cut_range[1])] 45 | if bessel: 46 | inter_mode = 'bessel' ; bes_txt = 'bessel' 47 | else: 48 | inter_mode = None ; bes_txt = '' 49 | for nam in names: 50 | npy = np.load(PATH+mapa+folder+nam+'.npy'); print(nam+'.npy.shape: ', npy.shape) 51 | if perspective == 'Z': 52 | if RGB_mode: 53 | plt.imshow(npy[layer,:,:cutoff_limit,:], interpolation=inter_mode) 54 | else: 55 | plt.imshow(npy[layer,:,:cutoff_limit], interpolation=inter_mode) 56 | elif perspective == 'X': 57 | plt.imshow(npy[:,layer,:,:], origin='lower', interpolation=inter_mode) 58 | elif perspective == 'Y': 59 | plt.imshow(npy[:,:,layer,:], origin='lower', interpolation=inter_mode) 60 | plt.gca().set_axis_off() 61 | plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, hspace = 0, wspace = 0) 62 | plt.margins(0,0) 63 | plt.gca().xaxis.set_major_locator(plt.NullLocator()) 64 | plt.gca().yaxis.set_major_locator(plt.NullLocator()) 65 | if names.index(nam)== cut_range[0]: 66 | plast_mikroni = str("{:>8.3f}".format((plast-(plast_range[1]-1))* 0.625))+u" \u00B5m" 67 | plt.text(1,5, plast_mikroni, color='white', fontsize=22) 68 | elif names.index(nam)== cut_range[1]-1: 69 | l_edge = 50-int(marker_size/cell) 70 | plt.hlines(80, l_edge,50, color='white', label='5', linewidth=5) 71 | plt.text(l_edge, 88,str(marker_size)+' '+u"\u00B5m", color='white', fontsize=22) 72 | plt.savefig(PATH+mapa+folder+nam+' '+perspective+'='+str(layer)+' '+bes_txt+'.png', bbox_inches='tight', pad_inches = 0) 73 | plt.clf() 74 | print() 75 | 76 | #X_cutoff_percent = 25 ; X_cutoff = int(X_cutoff_percent * X / 100) # Analogy with Hatch Spacing 77 | 78 | tracks_RGB = {'Track_0' : {'dir': 'Track_0/cuts_RGB/', 'X_cutoff': 48 , }, 79 | 'Track_1' : {'dir': 'Track_1/cuts_RGB/', 'X_cutoff': 24 , }, 80 | 'Track_2' : {'dir': 'Track_2/cuts_RGB/', 'X_cutoff': 0 , }, 81 | } 82 | 83 | tracks_faza = {'Track_0' : {'dir': 'Track_0/cuts_faza/', 'X_cutoff': 48 , }, 84 | 'Track_1' : {'dir': 'Track_1/cuts_faza/', 'X_cutoff': 24 , }, 85 | 'Track_2' : {'dir': 'Track_2/cuts_faza/', 'X_cutoff': 0 , }, 86 | } 87 | 88 | 89 | zip_folder = 'Tracks (0,1,2) zipped/' # folder 90 | zip_file_RGB = 'Zip_RGB_' # fileroot 91 | zip_file_faza = 'Zip_faza_' 92 | 93 | 94 | zipping_tracks = ['Track_0', 'Track_1', 'Track_2', ] 95 | 96 | 97 | def Zip_and_Cut(folder, fileroot, perspective, layer): 98 | names = [fileroot+'{}'.format(i) for i in range (cut_range[0], cut_range[1])] 99 | if bessel: 100 | inter_mode = 'bessel' ; bes_txt = 'bessel' 101 | else: 102 | inter_mode = None ; bes_txt = '' 103 | for nam in names: 104 | VC =[] 105 | for tra in zipping_tracks: 106 | if RGB_mode: 107 | npy = np.load(PATH+mapa+tracks_RGB[tra]['dir']+nam+'.npy'); print(nam+'.npy.shape: ', npy.shape) 108 | VC.append([npy, tracks_RGB[tra]['X_cutoff']]) 109 | 110 | if perspective == 'Z': 111 | if len(VC)==2: 112 | out = np.hstack((VC[1][0][:,VC[1][1]:,:cutoff_limit,:], VC[0][0][:,VC[0][1]:,:cutoff_limit,:] )) 113 | 114 | elif len(VC)==3: 115 | out = np.hstack((VC[2][0][:,VC[2][1]:,:cutoff_limit,:], out )) 116 | del VC[0] 117 | 118 | else: 119 | npy = np.load(PATH+mapa+tracks_faza[tra]['dir']+nam+'.npy'); print(nam+'.npy.shape: ', npy.shape) 120 | VC.append([npy, tracks_faza[tra]['X_cutoff']]) 121 | 122 | if perspective == 'Z': 123 | if len(VC)==2: 124 | out = np.hstack((VC[1][0][:,VC[1][1]:,:cutoff_limit], VC[0][0][:,VC[0][1]:,:cutoff_limit] )) 125 | 126 | elif len(VC)==3: 127 | out = np.hstack((VC[2][0][:,VC[2][1]:,:cutoff_limit], out )) 128 | del VC[0] 129 | 130 | #plt.imshow(VC[0][0][:,VC[0][1]:,:,:][0]); plt.title('Track_0') 131 | #plt.figure(); plt.imshow(VC[1][0][:,VC[1][1]:,:,:][0]); plt.title('Track_1') 132 | #plt.figure() 133 | plt.imshow(out[0], interpolation=inter_mode) 134 | plt.gca().set_axis_off() 135 | plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, hspace = 0, wspace = 0) 136 | plt.margins(0,0) 137 | plt.gca().xaxis.set_major_locator(plt.NullLocator()) 138 | plt.gca().yaxis.set_major_locator(plt.NullLocator()) 139 | nam = nam.replace('cut', 'Zip') 140 | plt.savefig(PATH+mapa+folder+nam+' '+perspective+'='+str(layer)+' '+bes_txt+'.png', bbox_inches='tight', pad_inches = 0) 141 | 142 | 143 | def Combine_Pictures_Horizontally(folder, fileroot, final, perspective, layer): 144 | if bessel: 145 | bes_txt = 'bessel' 146 | else: 147 | bes_txt = '' 148 | names = [fileroot+'{0} {1}={2} {3}'.format(i, perspective,layer,bes_txt) for i in range (cut_range[0], cut_range[1])] 149 | images = [Image.open(PATH+mapa+folder+nam+'.png') for nam in names] 150 | widths, heights = zip(*(i.size for i in images)) 151 | total_width = sum(widths) 152 | max_height = max(heights) 153 | if RGB_mode: 154 | new_im = Image.new('RGB', (total_width, max_height)) 155 | else: 156 | new_im = Image.new('RGB', (total_width, max_height)) 157 | x_offset = 0 158 | for im in images: 159 | new_im.paste(im, (x_offset,0)) 160 | x_offset += im.size[0] 161 | plt.imshow(new_im) 162 | new_im.save(PATH+mapa+folder+final) 163 | 164 | 165 | #********************************************************************************************************************************************* 166 | ''' ------------------------------------------------------------------ execution -------------------------------------------------------------------------''' 167 | 168 | for plast in range(plast_range[0], plast_range[1]): 169 | if RGB_mode: 170 | if bessel: 171 | result = 'RGB_final bessel, {0}= {1}.png'.format(perspektiva, plast) 172 | else: 173 | result = 'RGB_final, {0}= {1}.png'.format(perspektiva, plast) 174 | if zipping: 175 | zip_final = 'zipped_final_RGB.png' 176 | Zip_and_Cut(zip_folder, cut_file_RGB, perspektiva, plast) 177 | Combine_Pictures_Horizontally(zip_folder, zip_file_RGB, zip_final, perspektiva, plast) 178 | else: 179 | Cut_Pictures(cuts_RGB, cut_file_RGB, perspektiva, plast) 180 | Combine_Pictures_Horizontally(cuts_RGB, cut_file_RGB, result,perspektiva, plast) 181 | 182 | else: 183 | if bessel: 184 | result = 'faza_final bessel, {0}= {1}.png'.format(perspektiva, plast) 185 | else: 186 | result = 'faza_final, {0}= {1}.png'.format(perspektiva, plast) 187 | if zipping: 188 | zip_final = 'zipped_final_faza.png' 189 | Zip_and_Cut(zip_folder, cut_file_faza, perspektiva, plast) 190 | #Combine_Pictures_Horizontally(zip_folder, zip_file_faza, zip_final, perspektiva, plast) 191 | else: 192 | Cut_Pictures(cuts_faza, cut_file_faza, perspektiva, plast) 193 | Combine_Pictures_Horizontally(cuts_faza, cut_file_faza, result,perspektiva, plast) 194 | 195 | plt.clf() 196 | 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /matrix_interpolation_special.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import shutil 4 | import numpy as np 5 | from scipy.ndimage.interpolation import map_coordinates 6 | import matplotlib.pyplot as plt 7 | import random, math, time 8 | plt.ion() 9 | 10 | #--------------------------------------------------------------------------------------------- F U N C T I O N S ---------------------------------------------# 11 | def m(pot, stevilo): 12 | q=np.load((pot+'salome_{}.npy').format(stevilo)) 13 | return q 14 | 15 | def N_Int_Files(sf, tf1, tf2, first): 16 | if first: 17 | SF_files = sf-1 18 | TF1_files = tf1 + (SF_files-2)*(tf1-1) 19 | TF2_files = tf2 + (TF1_files-2)*(tf2-1) 20 | else: 21 | SF_files = sf 22 | TF1_files = tf1 + (SF_files-2)*(tf1-1) 23 | TF2_files = tf2 + (TF1_files-1)*(tf2-1) 24 | return SF_files, TF1_files, TF2_files 25 | 26 | def Get_Sorted_File_List(): 27 | _path_, dirs, files = next(os.walk(ath)) 28 | nums = sorted([int(a[7:].split('.')[0])for a in files]) 29 | strings = [('salome_{}.npy').format(b) for b in nums] 30 | len_strings = len(files) 31 | return len_strings, strings 32 | 33 | def Merge_2_Space_Interpolated_NPYs(YP, TM, file_0, file_1): 34 | global Z,X,Y 35 | Snpy_0 = np.load(ath+file_0);Snpy_1 = np.load(ath+file_1) 36 | mat_4D = np.array([Snpy_0, Snpy_1]); del Snpy_0; del Snpy_1 37 | #file = ('salome_({0},{1}).npy').format(N, M) # two .npy files merged 38 | #np.save(ath+file, mat_4D) # saving merged .npy files 39 | Z = mat_4D.shape[1]; X = mat_4D.shape[2]; Y = mat_4D.shape[3] 40 | return mat_4D 41 | 42 | def Matrix_Interpolation(A): 43 | B_tuple = (time_factor, Z, X, Y) 44 | new_dims = [] 45 | for original_length, new_length in zip(A.shape, B_tuple): 46 | new_dims.append(np.linspace(0, original_length-1, new_length)) 47 | coords = np.meshgrid(*new_dims, indexing='ij') 48 | B = map_coordinates(A, coords, order=1) 49 | return B 50 | 51 | def Matrix_Time_Interpolation(YP, TM, cti, mapa_super, stp2): # time interpolation in given ../YP/TM folder over all space interpolated npy files 52 | global ath, TSC, counter, file_count, files 53 | ath = PATH+YP+'/'+TM+'/'+mapa_super+'/' 54 | mapa = 'time_factor_'+str(time_factor) 55 | print('Working in folder ../'+YP+'/'+TM+'/'+mapa_super+'/'+mapa) 56 | if not os.path.isdir(ath+mapa): 57 | os.mkdir(ath+mapa) 58 | file_count, files = Get_Sorted_File_List() 59 | TSC = []; tsc_counter = -1 60 | 61 | for i in range(file_count - 1): 62 | if i==0: 63 | tsc = [j for j in range(last, last + time_factor)] 64 | TSC.append(tsc) 65 | else: 66 | tsc = [j for j in range(tsc[-1]+1, tsc[-1]+time_factor)] 67 | TSC.append(tsc) 68 | tsc_counter -= 1 69 | 70 | start_total = time.time() 71 | for ii in range(file_count - 1): 72 | start = time.time(); counter = 0 73 | Matrix_4D = Merge_2_Space_Interpolated_NPYs(YP, TM, files[ii], files[ii+1]) 74 | inp_mat = Matrix_4D[:2, :, :, :] 75 | out_mat = Matrix_Interpolation(inp_mat); del inp_mat 76 | 77 | if ii==0: 78 | od=None 79 | else: 80 | od=1 81 | for j in out_mat[od:]: 82 | if tm_index >= cti: 83 | np.save(ath+mapa+'/salome_'+str(TSC[ii][counter])+'.npy', j) 84 | counter+=1 85 | end = time.time() 86 | 87 | # for connecting indivudal TR folders, i.e. last (pre-last, etc.) .npy file from working directory (say TR0) puts into next (TR1), which is created if not yet.. 88 | try: 89 | ath_next = PATH+YP+'/'+next_tm+'/'+mapa_super+'/' 90 | np.save(ath_next+mapa+'/salome_'+str(TSC[ii][counter-1])+'.npy', out_mat[-1])# last .npy file 91 | if stp2: 92 | np.save(ath_next+mapa+'/salome_'+str(TSC[ii][counter-2])+'.npy', out_mat[-2])# pre-last .npy file 93 | except FileNotFoundError: 94 | os.mkdir(ath_next+mapa) 95 | np.save(ath_next+mapa+'/salome_'+str(TSC[ii][counter-1])+'.npy', out_mat[-1])# last .npy file 96 | if stp2: 97 | np.save(ath_next+mapa+'/salome_'+str(TSC[ii][counter-2])+'.npy', out_mat[-2])# pre-last .npy file 98 | print('Total computing time = ',round(time.time()-start_total, 3),' seconds.'); print() 99 | 100 | 101 | def Delete_and_Move_files(YP, TM, F1, F2): 102 | print('Deleting and moving the files ..'); print() 103 | # 1st STEP:: Deleting only space interpolated .npyfiles from ..YP/TM folder 104 | mydir = PATH+YP+'/'+TM+'/' 105 | filelist = [f for f in os.listdir(mydir) if f.endswith(".npy") ] 106 | for f in filelist: 107 | os.remove(os.path.join(mydir, f)) 108 | 109 | # 2nd STEP:: Moving final time interpolated files from ..YP/TM/../../../time_factor_.. into ..YP/TM/ 110 | source_dir = mydir+F1+'/'+F2 111 | file_names = os.listdir(source_dir) 112 | for file_name in file_names[1:]: 113 | shutil.move(os.path.join(source_dir, file_name), mydir) 114 | 115 | # 3rd STEP:: Deleting ..YP/TM/time_factor_.. folder 116 | shutil.rmtree(mydir+F1) 117 | 118 | 119 | 120 | #--------------------------------------------------------------------------------------------------------------------------------------------------------------------# 121 | 122 | case = 'SLM_2D_Source' 123 | subcase = '0002/' 124 | subpath = 'INTER time=1, space=8 Z[0-9], X[15-27], Y[12-97], 1500°C, N=12/' 125 | #subpath = 'Testing_the_Toycode/' 126 | 127 | PATH = 'C:/sm-2018-w64-0-3/WORK/'+case+'_Files/post processing database/'+subcase+subpath 128 | 129 | 130 | # Creation of YPTM dictionary of YP folders and TM subfolders 131 | yp_dirs = [] 132 | for subdir in os.walk(PATH): 133 | yp_dirs.append(subdir) 134 | YP_dirlist = yp_dirs[0][1] 135 | 136 | YPTM = {} 137 | for ypdir in YP_dirlist: 138 | tm_dirs = [] 139 | for tmdir in os.walk(PATH+'/'+ypdir): 140 | tm_dirs.append(tmdir) 141 | YPTM[ypdir] = tm_dirs[0][1] 142 | 143 | # i.e. YPTM ={'YP0 [12,20]': ['TR1 [1,2]', 'TR2 [2,3]'], 'YP1 [19,27]': ['TR1 [1,2]', 'TR2 [2,3]']} 144 | 145 | 146 | # H contents ::: 'SF' (special folder of interpolated files from previous step), 'TF' (time factor of current step), 147 | # 'Last' (dictionary of starting indices of salome_{}.npy files of given time folders) 148 | 149 | 150 | H = {1:{'SF':'', 'TF':24, 'Last': {'TR0': None, 'TR1': 0, 'TR2': 139, 'TR3': 301, 151 | 'TR4': 463, 'TR5': 625, 'TR6': 787, 'TR7': 949, 152 | 'TR8': 1111, 'TR9': 1273, 'TR10': 1435, 'TR11': 1597, 153 | 'TR12': 1759, 'TR13': 1921, 'TR14': 2083, 'TR15': 2245, 154 | 155 | } 156 | }, # STEP 1 time interpolation 157 | 158 | 2: {'SF':'time_factor_24', 'TF':3, 'Last': {'TR0': None, 'TR1': 0, 'TR2': 277, 'TR3': 602, 159 | 'TR4': 927, 'TR5': 1252, 'TR6': 1577, 'TR7': 1902, 160 | 'TR8': 2227, 'TR9': 2552, 'TR10': 2877, 'TR11': 3202, 161 | 'TR12': 3527, 'TR13': 3852, 'TR14': 4177, 'TR15': 4502, 162 | } 163 | 164 | } # STEP 2 time interpolation 165 | } 166 | 167 | segments = ['YP0', 'YP1', 'YP2', 'YP3', 'YP4', 'YP5', 'YP6', 'YP7', 'YP8', 'YP9', 'YP10', 'YP11'] 168 | 169 | 170 | step_1 = True 171 | step_2 = True 172 | 173 | critical_time_index = 0 174 | 175 | 176 | delete = False 177 | 178 | ''' ................................................................. E X E C U T I O N .................................................''' 179 | ''' Iteration over given YP folders 180 | and TM subfolders in YPTM database ''' 181 | 182 | for yp in YPTM: 183 | 184 | if yp[:3] in segments[ 7 : 8 ]: # PICK YP segments from segments list 185 | tm_list = sorted(YPTM[yp], key=lambda x: int(x.split(' ')[0][2:])) 186 | 187 | for tm in tm_list [ 7 : 13 ]: # PICK TR time frames from corresponding YP folder 188 | tm_index = tm_list.index(tm) 189 | if step_1: 190 | 191 | STEP = 1 192 | print(20*'*'+' STEP = '+str(STEP)+' '+20*'*'); print() 193 | super_folder = H[STEP]['SF']; time_factor = H[STEP]['TF'] 194 | last = H[STEP]['Last'][tm.split(' ')[0]]; next_tm = tm_list[tm_index+1] 195 | Matrix_Time_Interpolation(yp, tm, critical_time_index, super_folder, False) 196 | print() 197 | #................... sys.exit()# >>> S . T . O . P . line STOP the execution <<< EXIT() ----- !! ! ! ! 198 | if step_2: 199 | STEP = 2 200 | print(20*'*'+' STEP = '+str(STEP)+' '+20*'*'); print() 201 | super_folder = H[STEP]['SF']; time_factor = H[STEP]['TF'] 202 | last = H[STEP]['Last'][tm.split(' ')[0]]; next_tm = tm_list[tm_index+1] 203 | Matrix_Time_Interpolation(yp, tm, critical_time_index, super_folder, True) 204 | 205 | if delete: 206 | Delete_and_Move_files(yp, tm, 'time_factor_10', 'time_factor_6') 207 | 208 | print(30*'-'+' DONE ! '+30*'-'); print() 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /pool_toycode.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Pool, Manager, freeze_support 2 | from functools import partial 3 | import numpy as np 4 | import itertools 5 | import matplotlib.pyplot as plt 6 | plt.ion() 7 | 8 | 9 | #--------------------------------------- GUI Tkinter part ---------------------------------------------------------------------------------- 10 | from tkinter import * 11 | 12 | root=Tk(); 13 | var0 = StringVar(); 14 | lab0 = Label(root, textvariable=var0, font=('Arial', '22')); lab0.grid(row=100, column=100) 15 | 16 | def stop_process(): 17 | root.after_cancel(pol) 18 | #--------------------------------------- GUI Tkinter part ---------------------------------------------------------------------------------- 19 | run_1st = True 20 | run_2nd = True 21 | run_3rd = True 22 | 23 | MPI = True 24 | 25 | # ~~~~ Manual Nucleation (MN)~~~~~~ 26 | Z,X,Y = 1, 11, 11 27 | faza = np.zeros((Z,X,Y)) 28 | cas = np.zeros((Z,X,Y)) 29 | dt = 1 30 | 31 | Negatives = {-1:0}; S = {} 32 | 33 | M = { 1: {'ß':(0, 3, 2),}, 34 | 3: {'ß':(0, 5, 6),}, 35 | 36 | } 37 | 38 | for i in M: 39 | faza[M[i]['ß'][0],M[i]['ß'][1],M[i]['ß'][2]]=i # define nucleus ID in faza matrix 40 | 41 | grain_ID = np.array([1, 3]) 42 | cas[np.isin(faza, grain_ID, invert=False)] = -1 43 | 44 | 45 | 46 | ''' ......................................... time counter PART :: function. . . ''' 47 | def time_counter(attr0, neg_index): # attr0= Negatives 48 | attr0[neg_index] += dt 49 | return attr0 50 | 51 | def time_counter_original(neg_index): 52 | global Negatives 53 | Negatives[neg_index] += dt 54 | return Negatives 55 | 56 | 57 | 58 | 59 | #Selection=[(1, '0_10'), (1, '01_1'), (1, '0_1_1'), (1, '001'), (1, '0_11'), (1, '010'), (1, '011'), (1, '00_1')] 60 | Selection=[(1, '001'), (1, '00_1'), (1, '010'), (1, '0_10'), 61 | (3, '001'), (3, '00_1'), (3, '010'), (3, '0_10'), 62 | ] 63 | #Selection=[(1, '001'), (1, '00_1')] 64 | 65 | #smeri=np.array(['001', '00_1', '010', '0_10', '011', '01_1', '0_11', '0_1_1'], dtype=' returns :: Negatives 87 | Negatives = TC_list[-1] 88 | print('Negatives after time_counter: ', Negatives) 89 | 90 | 91 | 92 | ''' ......................................... 2nd RUN --- MM_ multiprocessing pool function PART :: execution . . . ''' 93 | if run_2nd: 94 | if not MPI: 95 | q=list(itertools.product(smeri, Negatives)) 96 | MM_partial = partial( mpf.MM, Negatives, faza, grain_ID, cas, S) 97 | for qq in q: 98 | MM_list = [MM_partial(qq)] 99 | S = MM_list[-1] 100 | 101 | elif MPI: 102 | nega = sorted(list(Negatives.keys())) 103 | q=list(itertools.product(smeri, nega)) 104 | MM_list = p.map(partial( mpf.MM, Negatives, faza, grain_ID, cas, S), q) # --------> returns :: S 105 | #print('S[001]: ',MM_list[-1]['001'][0,2,3]) 106 | #print('S[00_1]: ',MM_list[-1]['00_1'][0,2,1]) 107 | #S = MM_list[-1] 108 | for j in MM_list: 109 | S.update(j) 110 | 111 | ''' ......................................... 3rd RUN --- GG_ multiprocessing pool function PART :: execution . . . ''' 112 | if run_3rd: 113 | if not MPI: 114 | F = faza.copy() 115 | #FF.append(faza) 116 | 117 | # Single-Core using Partial function 118 | GG_partial=partial( mpf.GG_, faza) 119 | for selsel in Selection: 120 | #GG_partial=partial( mpf.GG_, faza, cas, S) 121 | #GG_partial=partial( mpf.GG_, faza) 122 | faza = GG_partial(selsel) 123 | 124 | #cas = GG_list[1] 125 | #S = GG_list[2] 126 | if not np.all(faza==F): 127 | print('NOVA') 128 | negind = min(list(Negatives.keys()))- 1 # Here, negind should be defined as absolute counter of negative numbers to avoid erasing existing Negatives items 129 | for s in S: 130 | S[s][np.isin(faza-F, grain_ID)]= negind 131 | Negatives[negind]=0 132 | print(faza) 133 | 134 | ''' 135 | # Single-Core without Partial function 136 | GG_=mpf.GG_ 137 | for selsel in Selection: 138 | GG_list = GG_(faza,cas,S, selsel) 139 | faza=GG_list[0] 140 | cas=GG_list[1] 141 | S=GG_list[2] 142 | if not np.all(faza==F): 143 | print('NOVA') 144 | negind = min(list(Negatives.keys()))- 1 # Here, negind should be defined as absolute counter of negative numbers to avoid erasing existing Negatives items 145 | for s in S: 146 | S[s][np.isin(faza-F, grain_ID)]= negind 147 | Negatives[negind]=0 148 | print(faza) 149 | ''' 150 | 151 | elif MPI: 152 | F=faza 153 | GG_list=p.map(partial( mpf.GG_, faza), Selection) # --------> returns :: (faza) 154 | for gp in range(len(GG_list)-1): 155 | if gp==0: 156 | faza=np.where(GG_list[gp+1]==0, GG_list[gp], GG_list[gp+1]) 157 | else: 158 | faza=np.where(GG_list[gp+1]==0, faza, GG_list[gp+1]) 159 | 160 | 161 | #cas=np.where(S['00_1']==0, S['001'], S['00_1']) 162 | cas=S['001'] 163 | 164 | #l.acquire() 165 | #A[np.array([[[True,False,True]]])]=7 166 | #A=np.where(A==7,np.array([[[True,False,True]]]),7) 167 | #A=np.where(A==0,np.array([[[0,9,0]]]),7) 168 | #l.release() 169 | #cas=GG_list[0][1] 170 | #S=GG_list[-1][2] 171 | 172 | if not np.all(faza==F): 173 | print('faza and F are not equal') 174 | #negind -=1 175 | negind = min(list(Negatives.keys()))- 1 # Here, negind should be defined as absolute counter of negative numbers to avoid erasing existing Negatives items 176 | #for s in S._getvalue(): 177 | for s in S: 178 | S[s][np.isin(faza-F, grain_ID)]= negind 179 | Negatives[negind]=0 180 | 181 | 182 | if i>=END_step: 183 | root.after_cancel(pol) 184 | elif i(tresh+273)]=1 26 | p[:,:,col]=2 27 | 28 | axs[row, column].imshow(p[layer], cmap='jet') 29 | #axs[row].imshow(p[layer], cmap='jet') 30 | 31 | fig.suptitle(name+' : '+str(t_field.shape[0] )+' x '+str(t_field.shape[1] )+' x '+str(t_field.shape[2] )+' cells') 32 | #axs[0].xlabel(xlab, fontsize=16) 33 | 34 | def Stack_2 (yp1st, yp2nd, tm, cif, show_figure, layer, col, row, column): 35 | global tit, xax, axs 36 | yp_1st = Load_NPY(yp1st, tm, cif) 37 | yp_2nd = Load_NPY(yp2nd, tm, cif) 38 | yp_stacked = np.dstack((yp_1st,yp_2nd )) 39 | if show_figure: 40 | tit = 'YP'+str(yp1st[2:4])+'+YP'+str(yp2nd[2:4])+' --- salome_'+str(cif)+'.npy\n' 41 | xax = tm[:4]+' real time = '+str(round(cif*dt*1000, 3))+' msec.' 42 | P(yp_stacked, layer, Tm_C,tit+xax, xax, col, row, column) 43 | return yp_stacked 44 | 45 | def Make_Y_Partitions(Ymin, Ymax, slices): 46 | dDY = (Ymax-Ymin)/slices 47 | a=[Ymin+i*dDY for i in range(slices)] 48 | b=[Ymin+i*dDY+1 for i in range(1,slices+1)] 49 | YP={} 50 | for num,(i,j) in enumerate(zip(a,b)): 51 | YP['YP'+str(num)] = [int(i),int(j)] 52 | return YP 53 | 54 | 55 | ''' ................................. Interpolation data ....................................''' 56 | 57 | time_factor = 40 58 | space_factor = 8 59 | 60 | dt = 6.25e-06/space_factor # Real time step (interpolated); unit: SECONDS [s] 61 | Tm_C = 1507 # Melting Point in degrees Celsius 62 | ''' ................................................................................................ ''' 63 | 64 | y_min = 12 #16 65 | y_max = 97 66 | N = 12 # 80 67 | 68 | YP = Make_Y_Partitions(y_min, y_max-1, N) 69 | yp_list = [i+' '+str(YP[i]).replace(' ', '')for i in YP] 70 | 71 | tm_list = ['TR{0} [{0},{1}]'.format(i,i+1) for i in range (0,8)] 72 | 73 | #tm0 = 'TR0 [0,1]' 74 | #tm1 = 'TR1 [1,2]' 75 | #tm2 = 'TR2 [2,3]' 76 | #tm3 = 'TR3 [3,4]' 77 | #tm4 = 'TR4 [4,5]' 78 | #tm5 = 'TR5 [5,6]' 79 | 80 | #yp0 = 'YP0 [12,27]' 81 | #yp0 = 'YP0 [12,20]' 82 | 83 | #yp1 = 'YP1 [26,41]' 84 | #yp1 = 'YP1 [19,27]' 85 | 86 | #yp2 = 'YP2 [40,55]' 87 | #yp2 = 'YP2 [26,34]' 88 | 89 | 90 | #tm_list = [tm0, tm1, tm2, tm3, tm4, tm5] 91 | #yp_list = [yp0, yp1, yp2] 92 | 93 | 94 | ''' 1st PAIR ''' 95 | #S0 = Stack_2(yp0, yp1, tm0, 40, True) 96 | #S1 = Stack_2(yp0, yp1, tm0, 79, True) 97 | #S2 = Stack_2(yp0, yp1, tm1, 119, True) 98 | #S3 = Stack_2(yp0, yp1, tm2, 149, True) 99 | #Sa = Stack_2(yp0, yp1, tm3, 183, True) 100 | ''' 1st cut --- when melt leaves yp0, i.e. at ace time 183, then in CA yp0 faza is cut off and saved as .npy ''' 101 | 102 | ''' 2nd PAIR ''' 103 | #S4 = Stack_2(yp1, yp2, tm3, 183, True) 104 | #S5 = Stack_2(yp1, yp2, tm4, 239, True) 105 | 106 | 107 | '''**************************''' 108 | START_step = 271 # Starting time step number 109 | END_step = 1594 # Ending time step number 110 | '''**************************''' 111 | 112 | plast_T = 71 # Index of Z-layer to be shown in plt.imshow() ----> temperature field 113 | plast_CA = 0 # Index of Z-layer to be shown in plt.imshow() ----> microstructure 114 | 115 | 116 | Cut_Off_Percent = 50 # Percent of Stack_2 domain lenght at which this domain should be cut off ---> the left part is saved (.npy and/or .png)the right goes on to CA and so on and on and on.. 117 | 118 | CA_mode = False 119 | 120 | animate = False # False for clicking (or pressing Enter) Animate! button on GUI to show individual time step, True to click it only once and watch the animation 121 | shranjuj_animacijo = False # True to save each individual time frame image as .npy in order to make movie later on .. 122 | 123 | 124 | from tkinter import * 125 | root = Tk(); root.geometry('300x150+1100+600') 126 | 127 | korak = IntVar(); korak.set(START_step) 128 | 129 | tt = korak.get() 130 | tm_count = int((START_step+1)/(time_factor*space_factor)) 131 | 132 | yp_count = 0 133 | cut_count = -1 134 | 135 | fig, axs = plt.subplots(nrows=2, ncols=2, sharex=True, sharey=False, figsize=(5,8)) 136 | 137 | #yps_test=Stack_2(yp_list[yp_count], yp_list[yp_count+1], tm_list[tm_count], tt, False, plast_T, 0, 0, 0) 138 | #cutoff_limit = int(yps_test.shape[2]*Cut_Off_Percent/100) 139 | 140 | cutoff_limit = 64 141 | 142 | def ani(): 143 | global tt, tm_count, yp_count, cut_count, fig, axs, ani_run, npy 144 | try: 145 | if not CA_mode: 146 | yps1=Stack_2(yp_list[yp_count], yp_list[yp_count+1], tm_list[tm_count], tt, True, plast_T, cutoff_limit, 1,0) 147 | axs[1,0].set_title('salome_'+str(tt)+'.npy')#+' : '+str(t_field.shape[0] )+' x '+str(t_field.shape[1] )+' cells') 148 | axs[1,0].set_xlabel(xax, fontsize=16) 149 | 150 | #yps1=Stack_2(yp_list[yp_count], yp_list[yp_count+1], tm_list[tm_count], tt, True, plast_T-1, cutoff_limit, 1,1) 151 | #axs[1,1].set_title('salome_'+str(tt)+'.npy')#+' : '+str(t_field.shape[0] )+' x '+str(t_field.shape[1] )+' cells') 152 | #axs[1,1].set_xlabel(xax, fontsize=16) 153 | 154 | ''' 155 | if np.all(p[:,:,:cutoff_limit]==0): 156 | print(); print(50*'*',' CUT! ',50*'*') 157 | print('Cut_Off_Percent = ',Cut_Off_Percent,' % , cutoff limit = ',cutoff_limit) 158 | cut_text = 'Time step number '+str(tt)+', real time: '+str(round(1000*dt*tt, 3))+' msec.' 159 | print(cut_text) 160 | print(106*'*'); print() 161 | with open(PATH+mapa+'/cut_data.txt', 'a')as cuttxt: 162 | cuttxt.write(cut_text+'\n') 163 | 164 | yp_count+=1 165 | cut_count+=1 166 | 167 | plt.savefig(PATH+mapa+'/cut_'+str(cut_count)+'.png', bbox_inches='tight') 168 | np.save(PATH+mapa+'/cut_'+str(cut_count)+'.npy', p[:,:,:cutoff_limit]) 169 | 170 | ''' 171 | if CA_mode: 172 | npy = np.load(PATH+mapa+flashies+'/flashy_RGB_'+str(tt)+'.npy') 173 | plt.imshow(npy[plast_CA]) 174 | 175 | #axs[0,0].imshow(npy[plast_CA]) 176 | #axs[0,0].set_title('flashy_RGB_'+str(tt)+'.npy') 177 | #axs[0,0].set_xlabel('Z= '+str(plast_CA)) 178 | 179 | #axs[0,1].imshow(npy[0]) 180 | #axs[0,1].set_xlabel('Z=46') 181 | 182 | 183 | except FileNotFoundError: 184 | print(); print('FileNotFound Exception !') 185 | #print('STEP: ',tt,' , yp_count : ', yp_count,' tm_count : ',tm_count); print() 186 | 187 | tm_count+=1 188 | #yps1=Stack_2(yp_list[yp_count], yp_list[yp_count+1], tm_list[tm_count], tt, True, plast_T, cutoff_limit) 189 | 190 | yps1=Stack_2(yp_list[yp_count], yp_list[yp_count+1], tm_list[tm_count], tt, True, plast_T, cutoff_limit, 1,0) 191 | axs[1,0].set_title('salome_'+str(tt)+'.npy')#+' : '+str(t_field.shape[0] )+' x '+str(t_field.shape[1] )+' cells') 192 | axs[1,0].set_xlabel(xax, fontsize=16) 193 | 194 | yps1=Stack_2(yp_list[yp_count], yp_list[yp_count+1], tm_list[tm_count], tt, True, plast_T-1, cutoff_limit, 1,1) 195 | axs[1,1].set_title('salome_'+str(tt)+'.npy')#+' : '+str(t_field.shape[0] )+' x '+str(t_field.shape[1] )+' cells') 196 | axs[1,1].set_xlabel(xax, fontsize=16) 197 | 198 | 199 | if shranjuj_animacijo: 200 | try: 201 | plt.savefig(directory.get()+'/'+animation_figures+'/figure_'+str(tt)+'.png', bbox_inches='tight') 202 | except FileNotFoundError: 203 | os.mkdir(directory.get()+'/'+animation_figures) 204 | plt.savefig(directory.get()+'/'+animation_figures+'/figure_'+str(tt)+'.png', bbox_inches='tight') 205 | 206 | print('STEP: ',tt,' , yp_count : ', yp_count,' tm_count : ',tm_count) 207 | tt+=1 208 | 209 | if animate: 210 | ani_run=root.after(500,ani) 211 | 212 | 213 | ani_safety_switch = False 214 | def start_animation(): 215 | global ani_safety_switch 216 | if not ani_safety_switch: 217 | tt = korak.get() 218 | ani() 219 | if animate: 220 | ani_safety_switch=True 221 | else: 222 | ani_safety_switch=False 223 | 224 | def stop_animation(): 225 | global ani_safety_switch, tt 226 | ani_safety_switch=False 227 | try: 228 | root.after_cancel(ani_run) 229 | except NameError: 230 | pass 231 | tt= korak.get() 232 | 233 | return tt 234 | 235 | 236 | ent1= Entry(root, textvariable= korak, font=('Arial', '30'), justify='center', width=7); ent1.grid(row=19, column=11, columnspan=2, sticky=W) 237 | but5= Button(root, text= 'Animate!', font=('Arial', '22'), fg='green', width=9, command=start_animation); but5.grid(row=21, column=12, sticky=W) 238 | but6= Button(root, text= 'Stop', font=('Arial', '22'), fg='red', width=9, command=stop_animation); but6.grid(row=22, column=12, sticky=W) 239 | 240 | root.bind('', lambda event=None: but5.invoke()) # command to invoke but5 (Animate!) with Return (Enter) key on keyboard 241 | 242 | def on_enter(e): 243 | but5['background'] = 'red' 244 | 245 | def on_leave(e): 246 | but5['background'] = 'SystemButtonFace' 247 | 248 | but5.bind("", on_enter) 249 | but5.bind("", on_leave) 250 | -------------------------------------------------------------------------------- /matrix_interpolation.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | from scipy.ndimage.interpolation import map_coordinates 4 | import matplotlib.pyplot as plt 5 | import matplotlib.animation as animation 6 | import random, math, time 7 | plt.ion() 8 | 9 | # FE analysis result from SALOME 10 | 11 | case = 'SLM_2D_Source' 12 | subcase = '0002' 13 | 14 | PATH = 'C:/sm-2018-w64-0-3/WORK/'+case+'_Files/post processing database/'+subcase+'/' 15 | 16 | 17 | file = case+'_'+subcase+'.npy' # .npy filename with FE analysis results (after meshio_postprocessing.py) 18 | Matrix_4D = np.load(PATH+file) 19 | 20 | ''' ****************************************************************************************************************************************''' 21 | space_factor = 8 # Factor of spatial resolution increase 22 | 23 | FEM_time_factor = 1 # FEM time factor to make FEM analysis shorter ---> for this factor , i.e. diminish number of time steps 24 | extra_time_factor = 1 # ::: special time factor ::: to catch the mesh dependency effect !! ! ! 25 | 26 | 27 | time_factor = FEM_time_factor * extra_time_factor 28 | increase_tuple = (time_factor * space_factor, space_factor, space_factor, space_factor) # resolution increase factor by linear interpolation 29 | ''' ****************************************************************************************************************************************''' 30 | Time_Range = ( 1 , 14 ) 31 | 32 | long_track = True 33 | N = 12 # Number of equally sized partitions of the track 34 | yp = 'YP7' # Name of Y partition 35 | 36 | total_time_range =(1, 16) # total time range (number of FEM time steps)to set the domain constrains 37 | 38 | auto_reduce_domain_size = False # True to find the constrains and create mapa; False to make interpolations of individual time steps 39 | interpolation = True # False to make .npy file of each Matrix_4D time step; True to make time & space interpolation (scale up) of individual time step 40 | 41 | 42 | Tmelt_Celsius = 1500 # Melting point; unit: degrees C [deg. C] - for domain size reduction 43 | Tmelt= Tmelt_Celsius + 273 # Melting point; unit: KELVIN [K] 44 | 45 | TR_list = [i for i in range(Time_Range[0], Time_Range[1]+1)] 46 | 47 | ''' domain limits ----> reduction of FE domain to size a bit larger than the molten track, where the crystallization occurs .. ''' 48 | 49 | def Domain_Size_Reduction(domain, threshold): 50 | global z_min, z_max, x_min, x_max, y_min, y_max 51 | ax2=np.where(np.any(domain > threshold, axis=2)) 52 | ax1=np.where(np.any(domain > threshold, axis=1)) 53 | z_min = np.min(ax2[0]); z_max = np.max(ax2[0])+1 54 | x_min = np.min(ax2[1]); x_max = np.max(ax2[1])+1 55 | y_min = np.min(ax1[1]); y_max = np.max(ax1[1])+1 56 | 57 | reduced_domain = domain[z_min:z_max, x_min:x_max, y_min:y_max] 58 | return reduced_domain 59 | 60 | 61 | if auto_reduce_domain_size: 62 | limits = [ [], [], [], [], [], [] ] 63 | for i in range(total_time_range[0], total_time_range[1]+1): 64 | Domain_Size_Reduction(Matrix_4D[i], Tmelt) 65 | limits[0].append(z_min); limits[1].append(z_max) 66 | limits[2].append(x_min); limits[3].append(x_max) 67 | limits[4].append(y_min); limits[5].append(y_max) 68 | 69 | z_min, z_max, x_min, x_max, y_min, y_max = min(limits[0]), max(limits[1]), min(limits[2]), max(limits[3]), min(limits[4]), max(limits[5]) 70 | z_min = 7 71 | z_max = 8 72 | 73 | else: 74 | z_min = 0 #3 75 | z_max = 9 #9 76 | 77 | x_min = 15 # 15 --- for salome_4D 78 | x_max = 27 # 27 --- for salome_4D 79 | 80 | y_min = 12 # 12 --- for salome_4D 81 | y_max = 97 # 97 --- for salome_4D 82 | 83 | 84 | mapa = 'INTER time='+str(time_factor)+', space='+str(space_factor)+' Z['+str(z_min)+'-'+str(z_max)+'], X['+str(x_min)+'-'+str(x_max)+'], Y['+str(y_min)+'-'+str(y_max)+'], '+str(Tmelt_Celsius)+'°C'+', N='+str(N)+'/' 85 | 86 | if not os.path.isdir(PATH+mapa): 87 | os.mkdir(PATH+mapa) 88 | 89 | 90 | def f(x, tresh): 91 | T = np.load(PATH+mapa+subfolder+'/salome_'+str(x)+'.npy') 92 | P = np.zeros(T.shape) 93 | P[T >(tresh+273)]=1 94 | return T, P 95 | 96 | def p(t_field, tresh): 97 | p=np.zeros(t_field.shape) 98 | p[t_field>(tresh+273)]=1 99 | plt.imshow(p) 100 | 101 | def Matrix_Interpolation(A, it): 102 | if auto_reduce_domain_size: 103 | B_tuple = (it[0], (z_max-z_min)*it[1], (x_max-x_min)*it[2], (y_max-y_min)*it[3]) 104 | else: 105 | B_tuple = (it[0], A.shape[1]*it[1], A.shape[2]*it[2], A.shape[3]*it[3]) 106 | new_dims = [] 107 | for original_length, new_length in zip(A.shape, B_tuple): 108 | new_dims.append(np.linspace(0, original_length-1, new_length)) 109 | 110 | coords = np.meshgrid(*new_dims, indexing='ij') 111 | B = map_coordinates(A, coords, order=1) 112 | return B 113 | 114 | def TimeScaleCounter(tf,sf,tr): 115 | tsc = [i for i in range(tr[0]*tf*sf, tr[1]*tf*sf)] 116 | return tsc 117 | 118 | def Make_Y_Partitions(Ymin, Ymax, slices): 119 | dDY = (Ymax-Ymin)/slices 120 | a=[Ymin+i*dDY for i in range(slices)] 121 | b=[Ymin+i*dDY+1 for i in range(1,slices+1)] 122 | YP={} 123 | for num,(i,j) in enumerate(zip(a,b)): 124 | YP['YP'+str(num)] = (int(i), int(j)) 125 | return YP 126 | 127 | 128 | special_case = True 129 | 130 | ''' ..................... LONG track ............................................................................................................................................ ''' 131 | if long_track and not auto_reduce_domain_size: 132 | start_total = time.time() 133 | 134 | for time_snap in range(len(TR_list)-1): 135 | time_range = (TR_list[time_snap], TR_list[time_snap+1]) 136 | TSC = TimeScaleCounter(time_factor, space_factor, time_range) 137 | g = time_range[0] 138 | counter = 0 139 | 140 | YP = Make_Y_Partitions(y_min, y_max-1, N) 141 | 142 | for n in range(time_range[0], time_range[1]): 143 | yp_mapa = yp+' ['+str(YP[yp][0])+','+str(YP[yp][1])+']' 144 | if not os.path.isdir(PATH+mapa+yp_mapa): 145 | os.mkdir(PATH+mapa+yp_mapa+'/') 146 | print(35*'~') 147 | print('Processing time step ',n,'/',Time_Range[1]-1,' ..') 148 | start = time.time() 149 | if interpolation: 150 | #inp_mat = Matrix_4D[n:n+2, z_min:z_max, x_min:x_max, y_min:y_max] # different sizes of y ranges ---> y_max - y_min set by Domain_Size_Reduction()for given time_ranges 151 | inp_mat = Matrix_4D[n:n+2, z_min:z_max, x_min:x_max,YP[yp][0]:YP[yp][1]] # same sizes of y ranges, i.e. y_max-y_min, as defined in YP dictionary 152 | out_mat = Matrix_Interpolation(inp_mat,increase_tuple) 153 | if counter==0: 154 | od=None 155 | else: 156 | od=1 157 | del inp_mat 158 | 159 | else: 160 | out_mat = Matrix_4D[ : , z_min:z_max, x_min:x_max, y_min:y_max] 161 | od=None 162 | 163 | for i in out_mat[1:]: 164 | try: 165 | subfolder = '/TR'+str(n)+' ['+str(n)+','+str(n+1)+']' 166 | np.save(PATH+mapa+yp_mapa+subfolder+'/salome_'+str(TSC[counter]-g)+'.npy', i) 167 | except FileNotFoundError: 168 | os.mkdir(PATH+mapa+yp_mapa+subfolder) 169 | np.save(PATH+mapa+yp_mapa+subfolder+'/salome_'+str(TSC[counter]-g)+'.npy', i) 170 | counter+=1 171 | 172 | if special_case: # for connecting indivudal TR folders, i.e. last .npy file from working directory (say TR0) puts into next (TR1), which is created if not yet.. 173 | try: 174 | subf = '/TR'+str(n+1)+' ['+str(n+1)+','+str(n+2)+']' 175 | np.save(PATH+mapa+yp_mapa+subf+'/salome_'+str(TSC[counter-1]-g)+'.npy', out_mat[-1]) 176 | except FileNotFoundError: 177 | os.mkdir(PATH+mapa+yp_mapa+subf) 178 | np.save(PATH+mapa+yp_mapa+subf+'/salome_'+str(TSC[counter-1]-g)+'.npy', out_mat[-1]) 179 | 180 | end = time.time() 181 | print('Computing time: ',round(end-start, 3),' sec.') 182 | print(35*'~'); print() 183 | 184 | print('Total computing time = ',round(time.time()-start_total, 3),' seconds.') 185 | 186 | 187 | 188 | 189 | ''' ................. SHORT track ................................................................................................................................................''' 190 | if not long_track and not auto_reduce_domain_size: 191 | start_total = time.time() 192 | TSC = TimeScaleCounter(time_factor, space_factor, Time_Range) 193 | counter = 0 194 | for n in range(Time_Range[0], Time_Range[1]): 195 | print(35*'~') 196 | print('Processing time step ',n,'/',Time_Range[1]-1,' ..') 197 | start = time.time() 198 | inp_mat = Matrix_4D[n:n+2, z_min:z_max, x_min:x_max, y_min:y_max] 199 | out_mat = Matrix_Interpolation(inp_mat,increase_tuple); del inp_mat 200 | 201 | if counter==0: 202 | od=None 203 | else: 204 | od=1 205 | 206 | for i in out_mat[od:]: 207 | np.save(PATH+mapa+'/salome_'+str(TSC[counter])+'.npy', i) 208 | counter+=1 209 | end = time.time() 210 | print('Computing time: ',round(end-start, 3),' sec.') 211 | print(35*'~'); print() 212 | 213 | print('Total computing time = ',round(time.time()-start_total, 3),' seconds.') 214 | 215 | 216 | 217 | ''' ............................ checking the results ............................... ''' 218 | ''' 219 | maxi = np.where(np.max(mat_4d)== mat_4d) 220 | u=[4*i for i in range(time_range[0], time_range[1]+1)] 221 | plt.plot(u,mat_4d[:, maxi[1][0], maxi[2][0], 25,], marker='s', color='green', markersize=12) 222 | 223 | 224 | #plt.figure() 225 | v=[]; w=[] 226 | for i in range(21): 227 | w.append(i) 228 | q=np.load(PATH+mapa+'/salome_'+str(i)+'.npy') 229 | v.append(q[maxi[1][0], maxi[2][0], 25,]) 230 | 231 | 232 | plt.plot(w,v, marker='o', color='red') 233 | ''' 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | -------------------------------------------------------------------------------- /MPI_domain_splitting.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Pool, Process, Queue, Manager, Array, sharedctypes, set_start_method 2 | from functools import partial 3 | import itertools 4 | import time 5 | import numpy as np 6 | import matplotlib.pyplot as plt 7 | 8 | plt.ion() 9 | 10 | def merging(prva,druga): 11 | tot = np.where(druga==0, prva, druga) 12 | return tot 13 | 14 | def GG_pool(attr2, attr3): # attr3= faza, attr2= Selection 15 | grain=attr2[0]; s=attr2[1] 16 | ''' ----------------------------------------- GROUP 1 ::: [001], [010] >>> 4 sites -------------------------------------------''' 17 | if s == '001': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(0,0), (1,0)), 'constant')[:,:,:-1]==grain) , grain, attr3) 18 | elif s == '00_1': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(0,0), (0,1)), 'constant')[:,:,1:]==grain), grain, attr3) 19 | elif s == '010': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(1,0), (0,0)), 'constant')[:,:-1,:]==grain), grain, attr3) 20 | elif s == '0_10': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(0,1), (0,0)), 'constant')[:,1:,:]==grain), grain, attr3) 21 | elif s == '100': attr3= np.where((attr3==0)&(np.pad(attr3,((1,0),(0,0), (0,0)), 'constant')[:-1,:,:]==grain), grain, attr3) 22 | elif s == '_100': attr3= np.where((attr3==0)&(np.pad(attr3,((0,1),(0,0), (0,0)), 'constant')[1:,:,:]==grain), grain, attr3) 23 | return attr3 24 | 25 | 26 | def GG_process(Attr2, attr3, q): # attr3= faza, attr2= Selection, q= Queue() 27 | for attr2 in Attr2: 28 | grain=attr2[0]; s=attr2[1] 29 | ''' ----------------------------------------- GROUP 1 ::: [001], [010] >>> 4 sites -------------------------------------------''' 30 | if s == '001': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(0,0), (1,0)), 'constant')[:,:,:-1]==grain) , grain, attr3) 31 | elif s == '00_1': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(0,0), (0,1)), 'constant')[:,:,1:]==grain), grain, attr3) 32 | elif s == '010': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(1,0), (0,0)), 'constant')[:,:-1,:]==grain), grain, attr3) 33 | elif s == '0_10': attr3= np.where((attr3==0)&(np.pad(attr3,((0,0),(0,1), (0,0)), 'constant')[:,1:,:]==grain), grain, attr3) 34 | elif s == '100': attr3= np.where((attr3==0)&(np.pad(attr3,((1,0),(0,0), (0,0)), 'constant')[:-1,:,:]==grain), grain, attr3) 35 | elif s == '_100': attr3= np.where((attr3==0)&(np.pad(attr3,((0,1),(0,0), (0,0)), 'constant')[1:,:,:]==grain), grain, attr3) 36 | q.put(attr3) 37 | 38 | 39 | 40 | 41 | 42 | Z,X,Y = 1, 501, 1001 43 | 44 | A = np.zeros((Z, X, Y))# definition of initial, i.e. basic domain 45 | 46 | A[0,250,450] = 1 # "nucleation", state of cell 1 denotes solid state (grain_ID == 1), whereas 0 is for liquid 47 | A[0,330,660] = 2 48 | 49 | 50 | grain_ID = np.array([1,2]) 51 | smeri=np.array(['001', '00_1', '010', '0_10', '100', '_100',])[:4] 52 | Selection = list((itertools.product(grain_ID, smeri))) 53 | 54 | #from Long_track_CA_NEW_GUI import Selection_Mechanism, Random_Grains_n_Directions 55 | #Selection = Selection_Mechanism(grain_ID, smeri[:4], 7) 56 | 57 | 58 | 59 | domain_splitting_sequential = False 60 | domain_splitting_PARALLEL = True 61 | 62 | if domain_splitting_sequential: 63 | # .................. domain splitting ..................................................................... 64 | start_ds_sequential = time.time() 65 | Ycut_indices = [0, int(Y/2), Y] # splitting basic matrix into 2 partitions of equal size in Y-direction 66 | 67 | for i in range(20): 68 | # domain partitioning 69 | A1=A[:,:,Ycut_indices[0]:Ycut_indices[1]+1] # 1 st partition (in Y-direction) 70 | A2=A[:,:,Ycut_indices[1]-1:Ycut_indices[2]] # 2nd partition (in Y-direction) 71 | # transition function on 1st partition ( CPU1) 72 | for j in Selection: 73 | A1=GG_pool(j, A1) 74 | # transition function on 2nd partition ( CPU2) 75 | for j in Selection: 76 | A2=GG_pool(j, A2) 77 | A=np.dstack((A1[:,:,Ycut_indices[0]:Ycut_indices[1]], A2[:,:,1:])) # Stacking of arrays horizontally (in Y-direction) 78 | end_ds_sequential = time.time() 79 | print('Domain splitting computing time - sequential = ', round(end_ds_sequential-start_ds_sequential, 3),' sec.') 80 | 81 | 82 | 83 | 84 | if domain_splitting_PARALLEL: 85 | # .................. transformation of numpy arrays into sharedctypes ..................................................................... 86 | start_ds_parallel = time.time() 87 | Ycut_indices = [0, int(Y/2), Y] # splitting basic matrix into 2 partitions of equal size in Y-direction 88 | 89 | #A_ctype = np.ctypeslib.as_ctypes(A) 90 | #A = sharedctypes.Array(A_ctype._type_, A_ctype, lock=False) 91 | 92 | #A1=A[:,:,Ycut_indices[0]:Ycut_indices[1]+1] # 1st partition (in Y-direction) 93 | #A2=A[:,:,Ycut_indices[1]-1:Ycut_indices[2]] # 2nd partition (in Y-direction) 94 | 95 | #A1=A1.copy() 96 | #A1_ctype = np.ctypeslib.as_ctypes(A1) 97 | #A1 = sharedctypes.Array(A1_ctype._type_, A1_ctype, lock=True) 98 | 99 | #A2=A2.copy() 100 | #A2_ctype = np.ctypeslib.as_ctypes(A2) 101 | #A2 = sharedctypes.Array(A2_ctype._type_, A2_ctype, lock=True) 102 | 103 | if __name__ == '__main__': 104 | #pool = Pool(processes=2, initializer=initProcess, initargs=(A1, )) 105 | #pool = Pool(processes=2) 106 | set_start_method('spawn') 107 | manager=Manager() 108 | Q1=manager.Queue() 109 | Q2=manager.Queue() 110 | 111 | #work=[] 112 | for i in range(20): 113 | # --- domain partitioning --- 114 | #A1=np.frombuffer(A1_ctype).reshape((Z,X,int(Y/2)+1)) 115 | #A2=np.frombuffer(A2_ctype).reshape((Z,X,int(Y/2)+2)) 116 | 117 | A1=A[:,:,Ycut_indices[0]:Ycut_indices[1]+1] # 1st partition (in Y-direction) 118 | A2=A[:,:,Ycut_indices[1]-1:Ycut_indices[2]] # 2nd partition (in Y-direction) 119 | ''' 120 | A1=A1.copy(); A2=A2.copy() 121 | A1_ctype = np.ctypeslib.as_ctypes(A1) 122 | A1 = sharedctypes.Array(A1_ctype._type_, A1_ctype, lock=False) 123 | A2_ctype = np.ctypeslib.as_ctypes(A2) 124 | A2 = sharedctypes.Array(A2_ctype._type_, A2_ctype, lock=False) 125 | ''' 126 | ''' 127 | # transition function on 1st partition ( CPU1) 128 | for j in Selection: 129 | A1=GG_pool(j, A1) 130 | # transition function on 2nd partition ( CPU2) 131 | for j in Selection: 132 | A2=GG_pool(j, A2) 133 | ''' 134 | 135 | #for j in Selection: 136 | # A_list = pool.map(partial(GG_pool,j), [A1,A2] ) 137 | # A1,A2 = A_list[0], A_list[1] 138 | 139 | #work.append(pool.apply_async(GG_process,(Selection, A1))) 140 | 141 | p1 = Process(target=GG_process, args=(Selection, A1,Q1)) 142 | p2 = Process(target=GG_process, args=(Selection, A2,Q2)) 143 | 144 | p1.start() 145 | p2.start() 146 | 147 | A1=Q1.get() 148 | A2=Q2.get() 149 | 150 | p1.join() 151 | p2.join() 152 | 153 | A=np.dstack((A1[:,:,Ycut_indices[0]:Ycut_indices[1]], A2[:,:,1:])) # Stacking of arrays horizontally (in Y-direction) 154 | 155 | 156 | end_ds_parallel = time.time() 157 | print('Domain splitting computing time - parallel = ', round(end_ds_parallel-start_ds_parallel, 3),' sec.') 158 | 159 | 160 | 161 | #A=np.vstack((A1[:2],A2[1:])) # Stacking of arrays vertically (in Z-direction) 162 | ''' 163 | ds_start = time.time() 164 | if __name__ == '__main__': 165 | pool = Pool() 166 | for i in range(2): 167 | b=d[:3]; c=d[1:] 168 | for j in Selection: 169 | faza_list = pool.map(partial(GG_pool,j), [b,c] ) 170 | b,c=faza_list[0], faza_list[1] 171 | d=np.vstack((b[:2],c[1:])) 172 | ds_stop=time.time() 173 | print('MPI domain splitting computing time = ', int(ds_stop-ds_start),' sec.') 174 | pool.close() 175 | pool.join() 176 | ''' 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | single_core = False 193 | MPI_Pool = False 194 | MPI_Process = False 195 | 196 | if single_core: 197 | single_start = time.time() 198 | for i in range(100): 199 | for j in Selection: 200 | A=GG_pool(j, A) 201 | single_stop = time.time() 202 | print('Single Core computing time = ', round(single_stop-single_start, 3),' sec.') 203 | 204 | 205 | 206 | 207 | 208 | if MPI_Pool: 209 | mpi_start = time.time() 210 | if __name__ == '__main__': 211 | pool = Pool() 212 | for i in range(1): 213 | od=0; do=4 214 | for j in range(int(len(Selection)/4)): 215 | cpu_list = pool.map(partial(GG_pool, faza), Selection[od:do]) 216 | total=merging(cpu_list[0], cpu_list[1]) 217 | if len(cpu_list)> 2: 218 | for move in range(2, len(cpu_list)): 219 | total=merging(total, cpu_list[move]) 220 | faza = total.copy() 221 | od+=4; do+=4 222 | pool.close() 223 | pool.join() 224 | 225 | mpi_stop = time.time() 226 | print('MPI computing time = ', int(mpi_stop-mpi_start)) 227 | 228 | 229 | 230 | 231 | 232 | if MPI_Process: 233 | mpi_start = time.time() 234 | if __name__ == '__main__': 235 | 236 | for i in range(2): 237 | procesi=[] 238 | for j in Selection: 239 | p = Process(target=GG_pool, args=[faza,j]) 240 | p.start() 241 | procesi.append(p) 242 | 243 | for q in procesi: 244 | q.join() 245 | ''' 246 | # The tutorial from StackOverFlow, how Python for loop is paralelized 247 | # setup output lists 248 | output1 = list() 249 | output2 = list() 250 | output3 = list() 251 | 252 | for j in range(0, 10): 253 | # calc individual parameter value 254 | parameter = j * offset 255 | # call the calculation 256 | out1, out2, out3 = calc_stuff(parameter = parameter) 257 | 258 | # put results into correct output list 259 | output1.append(out1) 260 | output2.append(out2) 261 | output3.append(out3) 262 | 263 | 264 | pool = multiprocessing.Pool(4) 265 | out1, out2, out3 = zip(*pool.map(calc_stuff, range(0, 10 * offset, offset))) 266 | ''' 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | -------------------------------------------------------------------------------- /nucleation_backup.py: -------------------------------------------------------------------------------- 1 | ''' Program to help set the right parameters of nucleation and growth of grains during SLM ''' 2 | 3 | import numpy as np 4 | import random, math 5 | import matplotlib.pyplot as plt 6 | plt.ion() 7 | 8 | """ ===================================== F U N C T I O N S ================================================================""" 9 | 10 | def nukleacija_povrsina(pp): # heterogeneous nucleation (at the liquid-solid interface ---> melt-pool border) 11 | ''' parameters of heterogeneous nucleation''' 12 | ns_max = 5e10 # Number of new nuclei at optimal dT; unit: per SQUARE METER [m^-2] 13 | dTs_max0 = 2 # Optimal undercooling dT, where the formation of nuclei is the highest; unit: KELVIN [K] 14 | dTs_sigma = 0.5 # Standard deviation of Gaussian nuclei distribution [K] 15 | Ns_Nas = ns_max/(math.sqrt(2*math.pi))*math.e**(-(pp-dTs_max0)**2/(2*dTs_sigma**2)) 16 | return Ns_Nas 17 | 18 | def nukleacija_volumen(vv): # homogeneous nucleation 19 | ''' parameters of homogeneous nucleation ''' 20 | nv_max = 5e14 21 | dTv_max0 = 2 22 | dTv_sigma = 0.5 23 | Nv_Nav = nv_max/(math.sqrt(2*math.pi))*math.e**(-(vv-dTv_max0)**2/(2*dTv_sigma**2)) 24 | return Nv_Nav 25 | 26 | def nakljucje(msm): 27 | rand = np.random.random_sample(msm.shape) 28 | #rand = np.random.randint(0,100,(msm.shape)) 29 | #rand[taula==-1]=-1 30 | return rand 31 | 32 | def taljenje(u, Tm): # 'u' is temperature field, 'Tm' is melting point (K) 33 | global taula 34 | plt.clf() 35 | taula=np.zeros((Z,X,Y)) 36 | taula[uliquidus_temp]=-1 43 | return likvid 44 | 45 | # Loading temperature field (unit: KELVIN)in corresponding space (YP) and time (TR) related folder 46 | def Load_NPY(yp, tr, x): 47 | npy = np.load(PATH+mapa+yp+'/'+tr+time_factor_folder+'/salome_'+str(x)+'.npy') 48 | return npy 49 | 50 | def Stack_2 (yp1st, yp2nd, tm, cif): 51 | yp_1st = Load_NPY(yp1st, tm, cif) 52 | yp_2nd = Load_NPY(yp2nd, tm, cif) 53 | yp_stacked = np.dstack((yp_1st,yp_2nd )) 54 | return yp_stacked 55 | 56 | def growth_speed(dT_field): 57 | vg = 2.03e-4 * dT_field**2 - 0.544e-4 * dT_field 58 | return vg 59 | 60 | """ =====================================================================================================""" 61 | """ ==================================== F I L E S & F O L D E R S ========================================================""" 62 | 63 | case = 'SLM_2D_Source' ; subcase = '0002' 64 | PATH = 'C:/sm-2018-w64-0-3/WORK/'+case+'_Files/post processing database/'+subcase+'/' 65 | 66 | #mapa = 'INTER time=40, space=8 Z[7-8], X[15-27], Y[12-97], 1500°C, N=12/' 67 | mapa = 'INTER time=1, space=8 Z[0-9], X[15-27], Y[12-97], 1500°C, N=12/' 68 | 69 | time_factor_folder = '/time_factor_24/time_factor_3' 70 | """ =====================================================================================================""" 71 | 72 | YP0 = 'YP0 [12,20]' 73 | YP1 = 'YP1 [19,27]' 74 | 75 | TM = 'TR1 [1,2]' 76 | 77 | '''******************''' 78 | TIME_step = 10 79 | '''******************''' 80 | 81 | X = 96 82 | Y = 128 83 | z_min = 71 84 | z_max = 72 85 | 86 | Z = z_max - z_min 87 | 88 | faza = np.zeros((Z,X,Y)) 89 | NP = np.vectorize(nukleacija_povrsina) 90 | NV = np.vectorize(nukleacija_volumen) 91 | VG = np.vectorize(growth_speed) # matrix of growth velocity (vg) 92 | 93 | T = Stack_2(YP0, YP1, TM, TIME_step)[z_min:z_max] 94 | time_shift = 1 95 | T_next = Stack_2(YP0, YP1, TM, TIME_step+time_shift)[z_min:z_max] 96 | 97 | 98 | Tmelt_Celsius = 1507 ;Tmelt = Tmelt_Celsius + 273 # melting point (Tmelt is in Kelvin) 99 | dTt = T - Tmelt # undecooling [K] 100 | 101 | ''' Absolute liquidus temperature ''' 102 | dTliquidus = 50 103 | 104 | taljenje(T, Tmelt) # condition for melting ----> taula matrix of cell values; if value -1 then solid (or powder)elif value 0 then liquid 105 | liquidus(T,Tmelt+dTliquidus) # absolute liquidus line 106 | 107 | interface = NP(dTt) 108 | bulk = NV(dTt) 109 | live = nakljucje(taula) 110 | vg = VG(dTt) 111 | 112 | ß = 0 113 | 114 | 115 | """ ====================================>SHOWING the DATA<========================================================""" 116 | 117 | X_CUT = 6 ;'''............... X coordinate of the domain for 1D plotting ''' 118 | Y_CUT = 54 ;'''............... X coordinate of the domain for 1D plotting ''' 119 | 120 | # INTERFACE nuclei concentration PLOT(i.e. surface, heterogeneous nucleation..) vs. undercooling (dTt)in given range (delta_T) 121 | 122 | delta_T_min = 0 123 | delta_T_max = 4 124 | resolution = 200 125 | delta_T = [i/resolution for i in range(int(delta_T_min*resolution), int(delta_T_max*resolution))] 126 | interface_data = [NP(i) for i in delta_T] 127 | plt.plot(delta_T, interface_data, marker='.', color='magenta'); plt.xlabel(u"\u0394T ("+u"\u00B0C)", fontsize=16); plt.ylabel('Interface Nuclei Concentration', fontsize=16) 128 | 129 | 130 | # VG PLOT(i.e. vg)vs. undercooling (dTt)in given range (delta_T) 131 | ''' 132 | plt.figure() 133 | delta_T_min = -100 134 | delta_T_max = 0 135 | resolution = 200 136 | delta_T = [i/resolution for i in range(int(delta_T_min*resolution), int(delta_T_max*resolution))] 137 | vg_data = [VG(i) for i in delta_T] 138 | plt.plot(delta_T, vg_data, marker='.', color='#8000FF'); plt.xlabel(u"\u0394T ("+u"\u00B0C)", fontsize=16); plt.ylabel('Growth Velocity (m/s)', fontsize=16) 139 | ''' 140 | 141 | 142 | show_TEMPERATURE = True 143 | show_MELT_POOL = False 144 | show_UNDERCOOLING = False 145 | # Nucleation 146 | show_INTERFACE = False 147 | show_BULK = False 148 | show_LIVE = False 149 | # Growth 150 | show_GROWTH_VELOCITY = False 151 | show_LIQUIDUS = False 152 | 153 | '" Showing the TEMPERATURE field ''' 154 | if show_TEMPERATURE: 155 | plt.figure() 156 | plt.imshow(T[0],cmap='hot') 157 | ''' 158 | plt.plot(T[0,X_CUT,:], marker='.', color='green', label='time step: '+str(TIME_step)) 159 | plt.plot(T_next[0,X_CUT,:], marker='.', color='lime', label='time step: '+str(TIME_step+time_shift)) 160 | plt.title('TEMPERATURE, TIME step: '+str(TIME_step)) 161 | plt.xlabel('Y-axis'); plt.ylabel('Temperature (K)') 162 | plt.legend() 163 | ''' 164 | 165 | '" Showing the MELT POOL ''' 166 | if show_MELT_POOL: 167 | plt.figure() 168 | #plt.imshow(taula[0], cmap='hot') 169 | plt.plot(taula[0,X_CUT,:], marker='.', color='red') 170 | plt.title('MELT POOL, TIME step: '+str(TIME_step)) 171 | 172 | '" Showing the UNDERCOOLING field ''' 173 | if show_UNDERCOOLING: 174 | plt.figure() 175 | #dTt[dTt >= 2] = 0 # threshold 176 | #plt.imshow(dTt[0], cmap='jet') 177 | plt.plot(dTt[0,X_CUT,:], marker='.', color='blue') 178 | plt.title('UNDERCOOLING, TIME step: '+str(TIME_step)) 179 | 180 | '" Showing the INTERFACE field ''' 181 | if show_INTERFACE: 182 | plt.figure() 183 | #plt.imshow(interface[0], cmap='jet') 184 | plt.plot(interface[0,X_CUT,:], marker='.', color='magenta') 185 | plt.title('INTERFACE, TIME step: '+str(TIME_step)) 186 | 187 | '" Showing the BULK field ''' 188 | if show_BULK: 189 | plt.figure() 190 | #plt.imshow(bulk[0], cmap='jet') 191 | plt.plot(bulk[0,X_CUT,:], marker='.', color='orange') 192 | plt.title('BULK, TIME step: '+str(TIME_step)) 193 | 194 | '" Showing the LIVE field ''' 195 | if show_LIVE: 196 | plt.figure() 197 | #plt.imshow(live[0], cmap='jet') 198 | plt.plot(live[0,X_CUT,:], marker='.', color='black') 199 | plt.title('LIVE, TIME step: '+str(TIME_step)) 200 | 201 | 202 | '" Showing the GROWTH VELOCITY field ''' 203 | if show_GROWTH_VELOCITY: 204 | plt.figure() 205 | #plt.imshow(vg[0], cmap='jet') 206 | plt.plot(vg[0,X_CUT,:], marker='.', color='#8000FF') 207 | plt.title('GROWTH VELOCITY, TIME step: '+str(TIME_step)) 208 | 209 | '" Showing the LIQUIDUS field ''' 210 | if show_LIQUIDUS: 211 | plt.figure() 212 | #plt.imshow(likvid[0], cmap='hot') 213 | plt.plot(likvid[0,X_CUT,:], marker='.', color='red') 214 | plt.title('LIQUIDUS, TIME step: '+str(TIME_step)) 215 | 216 | 217 | 218 | PT = (0, X_CUT, Y_CUT) # Nucleation Point (NP) 219 | 220 | print(70*'*') 221 | print(15*' ','Nucleation point data at TIME step ',TIME_step);print() 222 | print(' z = ',PT[0]); print(' x = ',PT[1]); print(' y = ',PT[2]); print(' ß = ',ß); print(' M.P.: ',Tmelt,' K (',Tmelt_Celsius,u"\u00B0C)"); print() 223 | temp = round(T[PT[0],PT[1],PT[2],], 1) 224 | temp_next = round(T_next[PT[0],PT[1],PT[2],], 1) 225 | print('temperature: ', temp,' K (',temp-273,u"\u00B0C)") 226 | print('temperature next: ', temp_next,' K (',temp_next-273,u"\u00B0C)") 227 | melt_pool_int = taula[PT[0],PT[1],PT[2],] 228 | melt_pool_bool = True if melt_pool_int == 0 else False 229 | print('melt pool : ',melt_pool_bool,' (taula: ',melt_pool_int,')') 230 | print('undercooling : ', round(dTt[PT[0],PT[1],PT[2],], 3),' K') 231 | print('interface : ', round(interface[PT[0],PT[1],PT[2],], 4)) 232 | print('live : ', round(live[PT[0],PT[1],PT[2],], 4)) 233 | print() 234 | print('vg : ', round(1e3*vg[PT[0],PT[1],PT[2],], 4),' mm/s') 235 | print() 236 | print(40*'-') 237 | print('Booleans'); print(); booleans=[] 238 | print('taula: ',melt_pool_bool); booleans.append(melt_pool_bool) 239 | faza_bool = True if faza[PT[0],PT[1],PT[2],]==0 else False ; print('faza: ',faza_bool); booleans.append(faza_bool) 240 | live_inter_bool = True if live[PT[0],PT[1],PT[2],]ß else False; print('interface > ß: ',inter_beta_bool); booleans.append(inter_beta_bool) 242 | T_bool = True if T_next[PT[0],PT[1],PT[2],]ß) or (live[k][ii][j]/1ß))and T_next[k][ii][j] < T[k][ii][j]: 251 | 252 | # Growth Condition: 253 | # (faza==0) & (taula==0)& (likvid==0) &(lij>=Dsr_1st(R) )&(np.pad(faza,((0,0),(0,0), (1,0)), 'constant')[:,:,:-1]==grain), grain, faza) 254 | 255 | 256 | -------------------------------------------------------------------------------- /grain_growth_2D_Abaqus.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ Program za nukleacijo in rast zrn po FE analizi v programu ABAQUS, avtor: Andraž Kocjan 4 | Inštitut za kovinske materiale in tehnologije (IMT), Lepi pot 11, 1000 Ljubljana 5 | Februar, 2019 """ 6 | 7 | import sys 8 | import numpy as np 9 | import matplotlib.pyplot as plt 10 | import matplotlib.animation as animation 11 | import random, math, time 12 | plt.ion() 13 | 14 | # Rezultat FE analize v Abaqus-u 15 | PATH = 'C:/sm-2018-w64-0-3/WORK/SLM_2D_Source_Files/post processing database/0002/' 16 | file = 'SLM_2D_Source_0002.npy' 17 | Matrix_3D = np.load(PATH+file) 18 | 19 | matrix_2D = Matrix_3D[:,8,12:28,:] 20 | 21 | # N - širina, M - dolžina domene v številu celic, ki se ujema z FE mrežo 22 | 23 | N = 16 #matrix_2D.shape[1] 24 | M = matrix_2D.shape[2] 25 | 26 | time_frames = matrix_2D.shape[0] 27 | imported_time_matrix = matrix_2D.reshape(time_frames, N, M) 28 | 29 | nuk_num=1 30 | old_grid = np.zeros((nuk_num, N, M)) 31 | new_grid = np.zeros((nuk_num, N, M)) 32 | total_matrix=np.zeros((N,M)) 33 | 34 | """ -----------------------------------------------------------------------------------------------------------------------------""" 35 | ns_max = 5e10 # število novih nukleusov pri optimalni dT [m^-2] 36 | dTs_max0 = 2 # optimalna dT - kjer nastane največ nukleusov [K] 37 | dTs_sigma = 0.5 # standardna deviacija Gaussove porazdelitve števila nukleusov v odvisnosti od dT [K] 38 | 39 | nv_max = 5e14 # parametri nukleacije v tekočem analogija s parametri za površino 40 | dTv_max0 = 2 41 | dTv_sigma = 0.5 42 | 43 | def nukleacija_povrsina(pp): # heterogena nukleacija 44 | Ns_Nas = ns_max/(math.sqrt(2*3.1428))*math.e**(-(pp-dTs_max0)**2/(2*dTs_sigma**2)) 45 | return Ns_Nas 46 | 47 | def nukleacija_volumen(vv): # homogena nukleacija 48 | Nv_Nav = nv_max/(math.sqrt(2*3.1428))*math.e**(-(vv-dTv_max0)**2/(2*dTv_sigma**2)) 49 | #Nv_Nav=0 50 | return Nv_Nav 51 | 52 | nukleusi_pov = np.vectorize(nukleacija_povrsina) 53 | nukleusi_vol = np.vectorize(nukleacija_volumen) 54 | """ ---------------------------------------------------------------------------------------------------------------------------------""" 55 | """ OZNAKE STANJA CELIC """ 56 | 57 | st_prah = 0 # 0 - prah 58 | st_talina = 10 # 10 - talina 59 | st_haz = 5 # 5 - HAZ (heat affected zone) 60 | st_sled = 3 # 3 - sled (sintered track) 61 | """ ---------------------------------------------------- """ 62 | 63 | Tm_Celsius = 1507 # temperatura tališča v st. Celzija 64 | Tmelt= Tm_Celsius + 273 # temperatura tališča [K] 65 | Thaz = 1.2 * Tmelt # mejna temperatura HAZ-a [K] 66 | 67 | 68 | def nakljucje(msm): 69 | for x in range(N): 70 | for y in range(M): 71 | if msm[x][y]==0: 72 | msm[x][y]=random.randint(0,10) 73 | return msm 74 | 75 | 76 | P=np.zeros((N,M)) 77 | def phase(u, Tm): 78 | global P 79 | plt.clf() 80 | for x,i in enumerate(u): 81 | for y,j in enumerate(i): 82 | if j>=Tm: 83 | P[x][y]= st_talina # talina (melt_pool) 84 | elif j=Thaz: 85 | P[x][y]= st_haz # HAZ 86 | else: 87 | P[x][y]= st_prah # prah ALI h.a.z. ALI sled 88 | return P 89 | 90 | 91 | taula=np.zeros((N,M)) 92 | def taljenje(u, Tm): 93 | global taula 94 | plt.clf() 95 | for x,i in enumerate(u): 96 | for y,j in enumerate(i): 97 | if j>=Tm: 98 | taula[x][y]= 0 # talina 99 | else: 100 | taula[x][y]= -1 # prah ALI h.a.z. ALI sled 101 | return taula 102 | 103 | 104 | grain_counter=0 105 | def show_nuclei(interface, bulk, timesnap): 106 | global old_grid, new_grid, old_fresh, novi_nukleusi, grain_counter 107 | novi_nukleusi=[] 108 | live= nakljucje(taula) 109 | time_step = 1 110 | TEMP_now = imported_time_matrix[timesnap] 111 | """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dodano v 2020 ~~""" 112 | try: 113 | TEMP_next = imported_time_matrix[timesnap + time_step] 114 | except IndexError: 115 | pass 116 | """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~""" 117 | for i in range(N): 118 | for j in range(M): 119 | if taula[i][j]==0 and total_matrix[i][j]==0 and (live[i][j]/1 < interface[i][j] or live[i][j]/1 < bulk[i][j])and TEMP_next[i][j] < TEMP_now[i][j]: 120 | novi_nukleusi.append('nuk') 121 | grain_counter +=1 122 | #print(grain_counter) 123 | old_fresh= np.zeros((1, N,M)).astype(int) 124 | old_fresh[0][i][j]=1 125 | old_grid=np.concatenate([old_grid, old_fresh]) 126 | 127 | #print('novi nukleusi: ',len(novi_nukleusi),' grain_counter: ',grain_counter,' old_grid.shape: ',old_grid.shape) 128 | 129 | new_fresh=np.zeros((len(novi_nukleusi),N,M)).astype(int) 130 | new_grid=np.concatenate([new_grid,new_fresh]) 131 | return old_grid 132 | 133 | 134 | 135 | def Growth(count): 136 | global old_grid, new_grid 137 | 138 | for i in range(N): 139 | for j in range(M): 140 | if old_grid[count][i][j]==1 and taula[i][j]==0 and total_matrix[i][j]<2: 141 | new_grid[count][i][j]=1 142 | try: 143 | if new_grid[count][i][j+1]==0: 144 | new_grid[count][i][j+1]= 1 145 | except IndexError: 146 | pass 147 | try: 148 | if new_grid[count][i][abs(j-1)]==0: 149 | new_grid[count][i][abs(j-1)]= 1 150 | except IndexError : 151 | pass 152 | try: 153 | if new_grid[count][i+1][j]==0: 154 | new_grid[count][i+1][j]=1 155 | except IndexError : 156 | pass 157 | try: 158 | if new_grid[count][abs(i-1)][j]==0: 159 | new_grid[count][abs(i-1)][j]=1 160 | except IndexError : 161 | pass 162 | 163 | old_grid[count]=new_grid[count].copy() 164 | return old_grid[count] 165 | 166 | 167 | """ ------------------------------------------------------------------------------------------------------------""" 168 | def show_vg(dT_field): # it shows the interface growth rate (vg)vs. undercooling temperatures (dT_field)at given time step 169 | vg=2.03e-4 * dT_field**2 - 0.544e-4 * dT_field 170 | plt.clf() 171 | plt.imshow(vg, extent=(np.amin(xim), np.amax(xim), np.amin(yim), np.amax(yim)), cmap=plt.get_cmap('rainbow'), interpolation='bessel') 172 | #plt.plot(dT_field[1], vg[1]) 173 | #print('dT= ',dT_field[1][6],'vg= ',vg[1][6]) 174 | return vg 175 | 176 | def get_growth_length(dT_field, cas): 177 | vg=2.03e-4 * dT_field**2 - 0.544e-4 * dT_field 178 | length= vg*cas 179 | return length 180 | """ -----------------------------------------------------------------------------------------------------------""" 181 | 182 | def vsota(nuk_rate): 183 | global total_matrix 184 | plt.clf() 185 | """ Commenting cancels the grain-growth and only formation of nuclei is observed""" 186 | for i in range(nuk_rate): 187 | Growth(i) 188 | 189 | total_matrix=sum(old_grid[i] for i in range(nuk_rate)) 190 | plt.imshow(total_matrix) 191 | 192 | 193 | tt=-1 194 | def animate(i): 195 | global tt 196 | tt +=1 197 | plt.clf() 198 | try: 199 | T=imported_time_matrix[tt] 200 | taljenje(T, Tmelt) 201 | plt.imshow(taula) 202 | """ 203 | dTt = T - Tmelt # termično podhlajanje, kjer je T iz Abaqus-a uvožena matrika dejanskih temperatur posamezne celice 204 | nuk_matrix_pov=nukleusi_pov(dTt) 205 | nuk_matrix_vol=nukleusi_vol(dTt) 206 | show_nuclei(nuk_matrix_pov, nuk_matrix_vol, tt) 207 | """ 208 | #show_vg(dTt) 209 | #dolzine=get_growth_length(dTt,1) 210 | #print(dolzine[0]) 211 | """ 212 | nuks=len(old_grid) 213 | vsota(nuks) 214 | """ 215 | #for i in range(N): 216 | #for j in range(M): 217 | # if old_grid[i][j]==1: 218 | #print(dolzine[i][j], tt) 219 | except IndexError: 220 | print('Done..') 221 | ani.event_source.stop() 222 | 223 | # Odkomentiraj spodnje 4 vrstice, če želiš pognati animacija_sledi 224 | """ 225 | time_frames = time_frames 226 | temp=np.zeros((2,N,M)) # talina 227 | haz=np.zeros((2,N,M)) # talina +h.a.z. (heat affected zone) 228 | out=np.zeros((2,N,M)) # talina + sled 229 | """ 230 | 231 | tt=0 232 | def animacija_sledi(i): 233 | global tt 234 | tt+=1 235 | #print('---------------- frame number: ',tt,' -----------------') 236 | if ttMICROSTRUCTURE<============================================''' 34 | track = '2D 1st order Moore, real field/' 35 | 36 | flashies_RGB = track+'flashies_RGB/' # Subfolder with time-snap 3D matrices, i.e. flashies 37 | flashies_faza = track+'flashies_faza/' 38 | 39 | cuts_RGB = track+'cuts_RGB/' # Subfolder with cut 3D matrices, i.e. cuts 40 | cuts_faza = track+'cuts_faza/' 41 | '''=============================================================================================================''' 42 | 43 | '''===============================================>TEMPERATURE field<============================================''' 44 | 45 | YPN = ['YP0 [12,20]', 'YP1 [19,27]', 'YP2 [26,34]', 'YP3 [33,41]', 'YP4 [40,48]', 'YP5 [47,55]', ] 46 | TMN = ['TR0 [0,1]', 'TR1 [1,2]', 'TR2 [2,3]', 'TR3 [3,4]', 'TR4 [4,5]', 'TR5 [5,6]', 'TR6 [6,7]', 'TR7 [7,8]', 'TR8 [8,9]', 47 | 'TR9 [9,10]', 'TR10 [10,11]', 'TR11 [11,12]', 'TR12 [12,13]', 'TR13 [13,14]', 'TR14 [14,15]', 'TR15 [15,16]', 'TR16 [16,17]', ] 48 | 49 | '''**********************''' 50 | ypn_index = 0 #4 51 | tmn_index = 2 #8 52 | 53 | TIME_step = 0 #2392 54 | '''**********************''' 55 | 56 | YP0 = YPN[ypn_index] 57 | YP1 = YPN[ypn_index+1] 58 | TM = TMN[tmn_index] 59 | 60 | time_factor_folder = '/time_factor_24/time_factor_3' 61 | '''=============================================================================================================''' 62 | 63 | shranjuj_animacijo = False 64 | animation_figures = 'figures' 65 | cmap = 'jet' 66 | 67 | 68 | Tmelt = 1507 # Melting Point (in Celsius) 69 | dTliq = 50 70 | Tliquidus = Tmelt + dTliq # Liquidus line (in Celsius) 71 | dTund = -2 72 | Tunder= Tmelt + dTund # Undercooling (in Celsius) 73 | 74 | cell_size = 5e-06 / 8 # ..to calculate real dimensions of melt-pool 75 | #time_step = 5e-06 / 8 # for salome_4D 76 | 77 | temp_range = (3860, 298) # for SLM , COLORBAR Temperature range (vmax, vmin) for plt.colorbar showing Temp. scale; unit: deg. CELSIUS [deg. C] 78 | 79 | 80 | __name__='_' 81 | 82 | '''===================== GUI - grafični vmesnik za razrez 3D matrike in predstavitev v 2D ====================================================''' 83 | 84 | master = Tk(); master.geometry('1000x825+0+0'); master.title('Cut & Project by Andro') 85 | 86 | directory = StringVar() ; directory.set(PATH+mapa) 87 | micro_directory = StringVar(); micro_directory.set(PATH+mapa+flashies_RGB) 88 | micro_display = StringVar() ; micro_display.set('... '+micro_directory.get()[-75:]) 89 | temp_I_directory = StringVar(); temp_I_directory.set(PATH+mapa+YP0+'/'+TM+time_factor_folder+'/') 90 | temp_II_directory = StringVar(); temp_II_directory.set(PATH+mapa+YP1+'/'+TM+time_factor_folder+'/') 91 | temp1_display = StringVar(); temp2_display = StringVar() 92 | temp1_display.set('... '+temp_I_directory.get()[-75:]); temp2_display.set('... '+temp_II_directory.get()[-75:]) 93 | 94 | globina_micro = IntVar(); globina_micro.set(0) 95 | globina_temp = IntVar(); globina_temp.set(71) 96 | 97 | increment=IntVar(); increment.set(1) 98 | time_increment = IntVar(); time_increment.set(1) 99 | korak = IntVar(); korak.set(TIME_step) 100 | thresh = DoubleVar(); thresh.set(Tmelt) 101 | liquidus = DoubleVar() ; liquidus.set(Tliquidus) 102 | under = DoubleVar(); under.set(Tunder) 103 | 104 | lab1 = Label(master, text=' 2D projection of 3D microstructure, generated by CA', font=('Arial', '12')) 105 | lab1.grid(row=5, column=9, columnspan=4, sticky=W) 106 | 107 | lab2= Label (master, textvariable=directory, bg='black', fg='white', height=2, width=130) 108 | lab2.grid(row=6, column=10, columnspan=4, sticky=W) 109 | 110 | lab3= Label(master, text='AXIS: ', font=('Arial', '20')) 111 | lab3.grid(row=12, column=10, sticky=E) 112 | 113 | lab6= Label (master, text='', height=1) 114 | lab6.grid(row=13, column=10) 115 | 116 | lab4= Label(master, text=' Depth: ', font=('Arial', '20')) 117 | lab4.grid(row=14, column=10, sticky=E) 118 | 119 | lab7= Label(master, text=' Depth Increment: ', font=('Arial', '14')) 120 | lab7.grid(row=15, column=10, sticky=NE) 121 | 122 | lab5= Label(master, text='', height=3) 123 | lab5.grid(row=16, column=10) 124 | 125 | v = IntVar(); v.set(2) 126 | rdb1= Radiobutton(master, text=" Z ", variable=v, value=2, font=('Arial', '20'), indicatoron=0, width=11) 127 | rdb2= Radiobutton(master, text=" X ", variable=v, value=0, font=('Arial', '20'), indicatoron=0, width=11) 128 | rdb3= Radiobutton(master, text=" Y ", variable=v, value=1, font=('Arial', '20'), indicatoron=0, width=11) 129 | rdb1.grid(row=12, column=11) 130 | rdb2.grid(row=12, column=12) 131 | rdb3.grid(row=12, column=13) 132 | 133 | ent1= Entry(master, textvariable= globina_micro, font=('Arial', '30'), justify='center', width=4) 134 | ent6 = Entry(master, textvariable= globina_temp, font=('Arial', '30'), justify='center', width=4) 135 | ent2= Entry(master, textvariable= increment, font=('Arial', '14'), justify='center', width=15) 136 | ent1.grid(row=14, column=11, sticky =W) 137 | ent6.grid(row=14, column=11, sticky=E) 138 | ent2.grid(row=15, column=11, sticky=N) 139 | 140 | lab20 = Label (master, textvariable=micro_display, bg='black', fg='lime', height=2, width=69, font=('Arial', '12'), justify='right') 141 | lab21 = Label (master, textvariable=temp1_display, bg='black', fg='#ffbf00', height=2, width=69, font=('Arial', '12'), justify='right') 142 | lab27 = Label (master, textvariable=temp2_display, bg='black', fg='#ffbf00', height=2, width=69, font=('Arial', '12'), justify='right') 143 | 144 | lab20.grid(row=8, column=10, columnspan=6, sticky=E) 145 | lab21.grid(row=9, column=10, columnspan=6, sticky=E) 146 | lab27.grid(row=10, column=10, columnspan=6, sticky=E) 147 | 148 | zdim = StringVar(); xdim = StringVar(); ydim = StringVar(); zdim_micro = StringVar() 149 | 150 | lab22= Label(master, text='Domain Dimensions (cells): ', font=('Arial', '16'), height=2) 151 | lab23 = Label (master, textvariable=zdim, bg='grey', fg='aqua', height=1, width=5, font=('Arial', '20')) 152 | lab28 = Label (master, textvariable=zdim_micro, bg='grey', fg='#ff99ff', height=1, width=6, font=('Arial', '20')) 153 | lab24 = Label (master, textvariable=xdim, bg='grey', fg='aqua', height=1, width=11, font=('Arial', '20')) 154 | lab25 = Label (master, textvariable=ydim, bg='grey', fg='aqua', height=1, width=11, font=('Arial', '20')) 155 | 156 | lab22.grid(row=11, column=10, sticky=E) 157 | lab23.grid(row=11, column=11, sticky=E) 158 | lab24.grid(row=11, column=12) 159 | lab25.grid(row=11, column=13) 160 | lab28.grid(row=11, column=11, sticky=W) 161 | 162 | def izberi_MICROSTRUCTURE_direktorij(): 163 | direktorij = directory.get() 164 | direktorij = filedialog.askdirectory() 165 | micro_directory.set(direktorij) 166 | micro_display.set('... '+direktorij[-75:]) 167 | 168 | def izberi_TEMPERATURE_I_direktorij(): 169 | direktorij = directory.get() 170 | direktorij = filedialog.askdirectory() 171 | temp_I_directory.set(direktorij) 172 | temp1_display.set('... '+direktorij[-75:]) 173 | 174 | def izberi_TEMPERATURE_II_direktorij(): 175 | direktorij = directory.get() 176 | direktorij = filedialog.askdirectory() 177 | temp_II_directory.set(direktorij) 178 | temp2_display.set('... '+direktorij[-75:]) 179 | 180 | 181 | 182 | '''===========================================================================================================================''' 183 | 184 | # Get time matrix 185 | def Load_Time_Step(num): 186 | global micro, Z,X,Y, field 187 | """ Temperature (Celsius)""" 188 | field=Stack_2(temp_I_directory.get(), temp_II_directory.get(), num)- 273 189 | 190 | Z=field.shape[0] ; Y=field.shape[1]; X=field.shape[2] 191 | zdim.set(str(Z)+' '); xdim.set(X); ydim.set(Y) 192 | """ Microstructure """ 193 | try: 194 | micro=np.load(micro_directory.get()+'/flashy_RGB_'+str(num)+'.npy') 195 | except FileNotFoundError: 196 | micro=np.zeros((Z,X,Y,3)) 197 | Zmicro = micro.shape[0] ; zdim_micro.set(' '+str(Zmicro)) 198 | 199 | 200 | # Funkcije razrezov 3D objekta v smereh Z, Y in X: 201 | 202 | from mpl_toolkits.axes_grid1 import make_axes_locatable 203 | 204 | f=plt.figure() 205 | g=f.gca() 206 | 207 | def cut_plane(figura, matrix1, matrix2, depth1, depth2, step): 208 | global barvni_kljuc, phase, x_dim 209 | 210 | thresh_melt = round((thresh.get()- Tmelt)*100/ Tmelt, 1) 211 | axs[0].set_title('MICROSTRUCTURE', fontsize=11) 212 | 213 | phase=np.full(matrix2.shape+(3,), (92, 92, 138)) # grey blue 214 | phase[matrix2>=under.get()]= (204,51,0) # red 215 | phase[matrix2>=thresh.get()]= (255,153,0) # orange 216 | phase[matrix2>=liquidus.get()]= (254,254,153) # light yellow 217 | 218 | e=np.zeros(phase.shape) 219 | p=phase[:,:,:,0] 220 | e[p==92]=0; e[p==255]=1 221 | 222 | if v.get()== 2: # Z_cut 223 | plt.ylabel('X'); plt.xlabel('Y') 224 | #fig.suptitle('Smer: Z, {0}% od začetka domene, TIME: {1} msec. (step # {2})'.format(round((depth+1)*100/Z, 1), "%6.3f" % (round(step*TIME_step*1000, 3)), step), fontsize=14) 225 | axs[0].imshow(matrix1[depth1,:,:], cmap=cmap, interpolation='bessel') 226 | axs[1].imshow(phase[depth2,:,:]) 227 | x_dim= np.int(np.max(np.sum(e[depth2,:,:],axis=0))*cell_size* 1e6) ; y_dim= np.int(np.max(np.sum(e[depth2,:,:],axis=1) )*cell_size*1e6) 228 | axs[1].set_title('MELT-POOL, X_size: '+str(x_dim)+u' \u03BCm, Y_size: '+str(y_dim)+u' \u03BCm, Tmelt = '+str(thresh.get())+u' \u2103') 229 | temp=matrix2[depth2,:,:] 230 | 231 | g.imshow(matrix1[depth1,:,:], interpolation=None) 232 | 233 | 234 | elif v.get()== 1: # Y_cut 235 | plt.ylabel('Z'); plt.xlabel('X') 236 | #fig.suptitle('Projekcija v smeri Y, {0}% od začetka domene, TIME: {1} msec. (step # {2})'.format(round(depth*100/X, 1), "%6.3f" % (round(step*TIME_step*1000, 3)), step), fontsize=14) 237 | #plt.gca().invert_yaxis() 238 | axs[0].imshow(matrix1[:,:,depth1], cmap=cmap, origin='lower', interpolation='bessel') 239 | axs[1].imshow(phase[:,:,depth2], origin='lower') 240 | x_dim= np.int(np.max(np.sum(e[:,:,depth2],axis=0))*cell_size* 1e6) ; y_dim= np.int(np.max(np.sum(e[:,:,depth2],axis=1) )*cell_size*1e6) 241 | axs[1].set_title('MELT-POOL, Z_size: '+str(x_dim)+u' \u03BCm, X_size: '+str(y_dim)+u' \u03BCm, Tmelt = '+str(thresh.get())+u' \u2103') 242 | temp=matrix2[:,:,depth2] 243 | 244 | g.imshow(matrix1[:,:,depth1], interpolation=None) 245 | 246 | elif v.get()== 0: # X_cut 247 | plt.ylabel('Z'); plt.xlabel('Y') 248 | #plt.suptitle('Projekcija v smeri X, {0}% od začetka domene, TIME: {1} msec. (step # {2})'.format(round(depth*100/Y, 1), "%6.3f" % (round(step*TIME_step*1000, 3)), step), fontsize=14) 249 | #plt.gca().invert_yaxis() 250 | axs[0].imshow(matrix1[:,depth1,:], cmap=cmap, origin='lower', interpolation='bessel') 251 | axs[1].imshow(phase[:,depth2,:], origin='lower') 252 | x_dim= np.int(np.max(np.sum(e[:,depth2,:],axis=0))*cell_size* 1e6) ; y_dim= np.int(np.max(np.sum(e[:,depth2,:],axis=1) )*cell_size*1e6) 253 | axs[1].set_title('MELT-POOL, Z_size: '+str(x_dim)+u' \u03BCm, Y_size: '+str(y_dim)+u' \u03BCm, Tmelt = '+str(thresh.get())+u' \u2103') 254 | temp=matrix2[:,depth2,:] 255 | 256 | g.imshow(matrix1[:,depth1,:], interpolation=None) 257 | 258 | 259 | 260 | Tmin=round(np.min(temp), 1); Tmax=round(np.max(temp), 1) 261 | ax2=axs[2].imshow(temp, cmap='hot', vmax=temp_range[0], vmin=temp_range[1], origin='lower', interpolation='bessel') 262 | axs[2].set_title('TEMPERATURE, Tmax = '+str(Tmax)+u' \u2103, Tmin = '+str(Tmin)+u' \u2103') 263 | 264 | divider = make_axes_locatable(axs[2]) 265 | cax2 = divider.append_axes("right", size="4%", pad=0.15) 266 | if bool(barvni_kljuc): 267 | barvni_kljuc.remove() 268 | barvni_kljuc = fig.colorbar(ax2, cax=cax2); barvni_kljuc.set_label('Temperature ['+u'\u2103]', rotation=90) 269 | 270 | 271 | fig, axs = plt.subplots(nrows=3, sharex=True, sharey=False, figsize=(5,8)); barvni_kljuc=False 272 | 273 | def prerez(direction): 274 | global fig, axs 275 | 276 | t=korak.get() 277 | if direction=='neutral': 278 | pass 279 | elif direction=='plus': 280 | t+= time_increment.get() 281 | elif direction=='minus': 282 | t-= time_increment.get() 283 | 284 | korak.set(t) 285 | Load_Time_Step(t); axis = v.get() 286 | a=globina_micro.get(); b=globina_temp.get() 287 | try: 288 | cut_plane(fig, micro, field, a,b, t) 289 | except _tkinter.TclError: 290 | fig, axs = plt.subplots(nrows=3, sharex=True, sharey=False, figsize=(5,8)); barvni_kljuc=False 291 | 292 | 293 | 294 | """ ------------------------------------- super cool (a.k.a. flashy) animation :) ------------------------------------- """ 295 | 296 | tt = korak.get() 297 | def ani(): 298 | global tt, fig, axs, ani_run 299 | try: 300 | Load_Time_Step(tt) 301 | except FileNotFoundError: 302 | master.after_cancel(ani_run) 303 | a=globina_micro.get(); axis = v.get() 304 | b=globina_temp.get() 305 | cut_plane(fig, micro, field, a, b, tt) 306 | if shranjuj_animacijo: 307 | try: 308 | plt.savefig(directory.get()+'/'+animation_figures+'/figure_'+str(tt)+'.png', bbox_inches='tight') 309 | except FileNotFoundError: 310 | os.mkdir(directory.get()+'/'+animation_figures) 311 | plt.savefig(directory.get()+'/'+animation_figures+'/figure_'+str(tt)+'.png', bbox_inches='tight') 312 | tt+=1 313 | 314 | ani_run=master.after(300,ani) 315 | 316 | 317 | ani_safety_switch = False 318 | def start_animation(): 319 | global ani_safety_switch 320 | if not ani_safety_switch: 321 | ani(); ani_safety_switch=True 322 | 323 | def stop_animation(): 324 | global ani_safety_switch, tt 325 | ani_safety_switch=False 326 | try: 327 | master.after_cancel(ani_run) 328 | except NameError: 329 | pass 330 | tt= korak.get() 331 | return tt 332 | 333 | 334 | 335 | """++++++++++++++++++++++++++++ FAST creation of .png animation figures by multiprocessing +++++++++++++++++++++++++++++++++++++++++++++++""" 336 | ''' 337 | import multiprocessing 338 | import concurrent.futures 339 | 340 | first = 10 341 | last = 233 342 | picker = 1 343 | g= 9 344 | smer = 2 345 | 346 | def fast_image_saver(im_counter, a, axis): 347 | global fig, axs 348 | Load_Time_Step(im_counter) 349 | #a=globina.get(); axis = v.get() 350 | b=int(a) 351 | cut_plane(fig, micro, field, b, im_counter) 352 | try: 353 | plt.savefig(directory.get()+'/'+animation_figures+'/figure_'+str(im_counter)+'.png', bbox_inches='tight') 354 | except FileNotFoundError: 355 | os.mkdir(directory.get()+'/'+animation_figures) 356 | plt.savefig(directory.get()+'/'+animation_figures+'/figure_'+str(im_counter)+'.png', bbox_inches='tight') 357 | return im_counter 358 | 359 | 360 | if __name__ == '__main__': 361 | 362 | with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor: 363 | rezultati = [] 364 | for slika in range(first,last,picker): 365 | rezultati.append(executor.submit(fast_image_saver, slika, g, smer)) 366 | #fast_image_saver(slika, g, smer) 367 | 368 | out=[i.result()for i in rezultati] 369 | ''' 370 | """-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------""" 371 | 372 | def Shift_Cut(direction): 373 | a=globina_micro.get(); b=globina_temp.get() 374 | if direction=='plus': 375 | a+= increment.get(); b+= increment.get() 376 | elif direction=='minus': 377 | a-= increment.get(); b-= increment.get() 378 | 379 | H = {0:[int(xdim.get()), int(xdim.get())], 380 | 1:[int(ydim.get()), int(ydim.get())], 381 | 2:[int(zdim_micro.get()), int(zdim.get())],} 382 | 383 | axis = v.get() 384 | 385 | if (a>=0 and b>=0) and (a was pressed on a button!") 420 | e.widget.invoke() 421 | master.bind_class("Button","",wrapper) 422 | 423 | 424 | lab26= Label(master, text=' Time Increment: ', font=('Arial', '14')) 425 | lab26.grid(row=20, column=10, sticky=NE) 426 | 427 | ent5= Entry(master, textvariable= time_increment, font=('Arial', '14'), justify='center', width=15) 428 | ent5.grid(row=20, column=11, sticky=N) 429 | 430 | lab10= Label(master, text=' ') 431 | lab10.grid(row=21, column=9) 432 | 433 | '''..................... Showing temperature and phase fields .....................''' 434 | 435 | lab11= Label(master, text=' Temperature Treshold ['+u'\u2103]: ', font=('Arial', '20')) 436 | lab11.grid(row=25, column=10, sticky=E) 437 | 438 | ent4= Entry(master, textvariable= under, font=('Arial', '30'), justify='center', width=8, bg='#5c5c8a', fg='#cc3300') 439 | ent4.grid(row=25, column=11) 440 | 441 | ent7= Entry(master, textvariable= thresh, font=('Arial', '30'), justify='center', width=8, bg='#5c5c8a', fg='#ff9900') 442 | ent7.grid(row=25, column=12) 443 | 444 | ent8= Entry(master, textvariable= liquidus, font=('Arial', '30'), justify='center', width=8, bg='#5c5c8a', fg='#ffff99') 445 | ent8.grid(row=25, column=13) 446 | 447 | lab12= Label(master, text='undercooling', font=('Arial', '10')) 448 | lab12.grid(row=26, column=11) 449 | 450 | lab13= Label(master, text='melting point', font=('Arial', '10')) 451 | lab13.grid(row=26, column=12) 452 | 453 | lab14= Label(master, text='liquidus', font=('Arial', '10')) 454 | lab14.grid(row=26, column=13) 455 | 456 | lab15= Label(master, text=' '); lab15.grid(row=27, column=9) 457 | 458 | but4= Button(master, text= 'LOAD STEP', font=('Arial', '32'), bg='grey', fg='#ffff99', width=20, command=lambda:prerez('neutral'), height=1) 459 | but4.grid(row=28, column=10, columnspan=2) 460 | 461 | but5= Button(master, text= 'Animate!', font=('Arial', '22'), fg='green', width=10, command=start_animation, height=2) 462 | but5.grid(row=28, column=12) 463 | 464 | but6= Button(master, text= 'Stop', font=('Arial', '22'), fg='red', width=10, command=stop_animation, height=2) 465 | but6.grid(row=28, column=13) 466 | 467 | but7= Button(master, text= 'MICROSTRUCUTRES', font=('Arial', '15'), fg='lime', bg='grey', width=25, command=izberi_MICROSTRUCTURE_direktorij) 468 | but7.grid(row=8, column=10, columnspan=6,sticky=W) 469 | but8= Button(master, text= 'TEMPERATURES I', font=('Arial', '15'), fg='#ffbf00', bg='grey', width=25, command=izberi_TEMPERATURE_I_direktorij) 470 | but8.grid(row=9, column=10, columnspan=6,sticky=W) 471 | but11= Button(master, text= 'TEMPERATURES II', font=('Arial', '15'), fg='#ffbf00', bg='grey', width=25, command=izberi_TEMPERATURE_II_direktorij) 472 | but11.grid(row=10, column=10, columnspan=6,sticky=W) 473 | 474 | lab111= Label (master, text=20*'', height=2); lab111.grid(row=9, column=8, sticky=W) 475 | lab112= Label (master, text=20*'', height=2); lab112.grid(row=10, column=8) 476 | #master.mainloop() 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | -------------------------------------------------------------------------------- /grain_growth_2D_Abaqus_to_3D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ Program za nukleacijo in rast zrn po FE analizi v programu SALOME, avtor: Andraž Kocjan 4 | Inštitut za kovinske materiale in tehnologije (IMT), Lepi pot 11, 1000 Ljubljana 5 | Junij, 2020 """ 6 | 7 | import sys 8 | import numpy as np 9 | import matplotlib.pyplot as plt 10 | import matplotlib.animation as animation 11 | import random, math, time 12 | plt.ion() 13 | 14 | # Rezultat FE analize v Abaqus-u 15 | PATH = 'C:/sm-2018-w64-0-3/WORK/kode za Salome/Cellular Automata/' 16 | file = 'salome_0.npy' # oznaka simulacije: rp0_ss800_f5R8c4f8b23N30_7.5W_t1_fin 17 | zero_time_matrix = np.load(PATH+file) 18 | 19 | #matrix_2D = Matrix_3D[:,8,:,:] 20 | 21 | time_frames = 3 22 | Z = zero_time_matrix.shape[0] 23 | X = zero_time_matrix.shape[1] 24 | Y = zero_time_matrix.shape[2] 25 | 26 | 27 | #imported_time_matrix = Matrix_3D.reshape(time_frames, N, M) 28 | 29 | nuk_num=1 30 | old_grid = np.zeros((nuk_num, Z, X, Y)) 31 | new_grid = np.zeros((nuk_num, Z, X, Y)) 32 | total_matrix=np.zeros((Z,X,Y)) 33 | 34 | """ -----------------------------------------------------------------------------------------------------------------------------""" 35 | ns_max = 5e10 # število novih nukleusov pri optimalni dT [m^-2] 36 | dTs_max0 = 2 # optimalna dT - kjer nastane največ nukleusov [K] 37 | dTs_sigma = 0.5 # standardna deviacija Gaussove porazdelitve števila nukleusov v odvisnosti od dT [K] 38 | 39 | nv_max = 5e14 # parametri nukleacije v tekočem analogija s parametri za površino 40 | dTv_max0 = 2 41 | dTv_sigma = 0.5 42 | 43 | def nukleacija_povrsina(pp): # heterogena nukleacija 44 | Ns_Nas = ns_max/(math.sqrt(2*3.1428))*math.e**(-(pp-dTs_max0)**2/(2*dTs_sigma**2)) 45 | return Ns_Nas 46 | 47 | def nukleacija_volumen(vv): # homogena nukleacija 48 | Nv_Nav = nv_max/(math.sqrt(2*3.1428))*math.e**(-(vv-dTv_max0)**2/(2*dTv_sigma**2)) 49 | #Nv_Nav=0 50 | return Nv_Nav 51 | 52 | nukleusi_pov = np.vectorize(nukleacija_povrsina) 53 | nukleusi_vol = np.vectorize(nukleacija_volumen) 54 | """ ---------------------------------------------------------------------------------------------------------------------------------""" 55 | """ OZNAKE STANJA CELIC """ 56 | 57 | st_prah = 0 # 0 - prah 58 | st_talina = 10 # 10 - talina 59 | st_haz = 5 # 5 - HAZ (heat affected zone) 60 | st_sled = 3 # 3 - sled (sintered track) 61 | """ ---------------------------------------------------- """ 62 | 63 | Tm_Celsius = 900 # temperatura tališča v st. Celzija 64 | Tmelt= Tm_Celsius + 273 # temperatura tališča [K] 65 | Thaz = 1.2 * Tmelt # mejna temperatura HAZ-a [K] 66 | 67 | 68 | def nakljucje(msm): 69 | for z in range(Z): 70 | for x in range(X): 71 | for y in range(Y): 72 | if msm[z][x][y]==0: 73 | msm[z][x][y]=random.randint(0,10) 74 | return msm 75 | 76 | """ ~~~~~~~~~~~~~~~~~~~~~~~~ za prikaz staljene cone ~~~~~~~~~~~~~""" 77 | P=np.zeros((Z,X,Y)) 78 | def phase(u, Tm): 79 | global P 80 | plt.clf() 81 | for x,i in enumerate(u): 82 | for y,j in enumerate(i): 83 | if j>=Tm: 84 | P[x][y]= st_talina # talina (melt_pool) 85 | elif j=Thaz: 86 | P[x][y]= st_haz # HAZ 87 | else: 88 | P[x][y]= st_prah # prah ALI h.a.z. ALI sled 89 | return P 90 | 91 | 92 | taula=np.zeros((Z,X,Y)) 93 | def taljenje(u, Tm): 94 | global taula 95 | plt.clf() 96 | for z,k in enumerate(u): 97 | for x,i in enumerate(k): 98 | for y,j in enumerate(i): 99 | if j>=Tm: 100 | taula[z][x][y]= 0 # talina 101 | else: 102 | taula[z][x][y]= -1 # prah ALI h.a.z. ALI sled 103 | return taula 104 | 105 | 106 | grain_counter=0 107 | def show_nuclei(interface, bulk, timesnap): 108 | global old_grid, new_grid, old_fresh, novi_nukleusi, grain_counter 109 | novi_nukleusi=[] 110 | live= nakljucje(taula) 111 | time_step = 1 112 | #TEMP_now = Matrix_3D[timesnap] 113 | TEMP_now = np.load('salome_'+str(timesnap)+'.npy') 114 | """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dodano v 2020 ~~""" 115 | try: 116 | #TEMP_next = Matrix_3D[timesnap + time_step] 117 | TEMP_next = np.load('salome_'+str(timesnap+time_step)+'.npy') 118 | print('TEMP_next.shape: ', TEMP_next.shape) 119 | except IndexError: 120 | raise IndexError('zmanjkalo je časovnih korakov...') 121 | """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~""" 122 | for k in range(Z): 123 | for i in range(X): 124 | for j in range(Y): 125 | if taula[k][i][j]==0 and total_matrix[k][i][j]==0 and (live[k][i][j]/1 < interface[k][i][j] or live[k][i][j]/1 < bulk[k][i][j])and TEMP_next[k][i][j] < TEMP_now[k][i][j]: 126 | novi_nukleusi.append('nuk') 127 | grain_counter +=1 128 | #print(grain_counter) 129 | old_fresh= np.zeros((1, Z,X,Y)).astype(int) 130 | old_fresh[0][k][i][j]=1 131 | old_grid=np.concatenate([old_grid, old_fresh]) 132 | 133 | #print('novi nukleusi: ',len(novi_nukleusi),' grain_counter: ',grain_counter,' old_grid.shape: ',old_grid.shape) 134 | 135 | new_fresh=np.zeros((len(novi_nukleusi),Z,X,Y)).astype(int) 136 | new_grid=np.concatenate([new_grid,new_fresh]) 137 | return old_grid 138 | 139 | 140 | """ Definicija smeri kristalizacije 141 | 142 | dlup up drup 143 | \ | / 144 | \ | / 145 | left ----- 0,0 ----- right 146 | / | \ 147 | / | \ 148 | dldown down drdown 149 | 150 | Legenda: 151 | 152 | left ..... horizontal-left , right .... horizontal-right 153 | up ..... vertical-up , down .... vertical-down 154 | 155 | primer za diagonale: dlup = d-l-up ===> d.... diagonal, l .... left, up ... up 156 | """ 157 | vertical=1 158 | horizontal=1 159 | diagonal_right=1 160 | diagonal_left=1 161 | 162 | z_00=1 163 | 164 | orient_matrix = [vertical, horizontal, diagonal_right, diagonal_left, z_00] 165 | 166 | def Growth(count, om): 167 | global old_grid, new_grid 168 | 169 | for k in range(Z): 170 | for i in range(X): 171 | for j in range(Y): 172 | if old_grid[count][k][i][j]==1 and taula[k][i][j]==0 and total_matrix[k][i][j]<2: # pogoj za zacetek rasti - obstoj nukleusa (vrednost celice = 1) 173 | new_grid[count][k][i][j]=1 174 | # smer: --------------------------------------- up ------ 175 | try: 176 | if new_grid[count][k][i][j+om[0]]==0: 177 | new_grid[count][k][i][j+om[0]]= 1 178 | except IndexError: 179 | pass 180 | # smer: ------------------------------------ down ----- 181 | try: 182 | if new_grid[count][k][i][abs(j-om[0])]==0: 183 | new_grid[count][k][i][abs(j-om[0])]= 1 184 | except IndexError : 185 | pass 186 | # smer: -------------------------------------- left ------ 187 | try: 188 | if new_grid[count][k][i-om[1]][j]==0: 189 | new_grid[count][k][i-om[1]][j]=1 190 | except IndexError : 191 | pass 192 | # smer: ------------------------------------- right ------ 193 | try: 194 | if new_grid[count][k][i+om[1]][j]==0: 195 | new_grid[count][k][i+om[1]][j]=1 196 | except IndexError : 197 | pass 198 | # smer: ------------------------------------- Z-axis UP (3D)------ 199 | try: 200 | if new_grid[count][k+om[4]][i][j]==0: 201 | new_grid[count][k+om[4]][i][j]=1 202 | except IndexError : 203 | pass 204 | # smer: ------------------------------------- Z-axis DOWN (3D)------ 205 | try: 206 | if new_grid[count][k-om[4]][i][j]==0: 207 | new_grid[count][k-om[4]][i][j]=1 208 | except IndexError : 209 | pass 210 | 211 | """ 212 | # diagonals 213 | # smer: ------------------------------------ dlup ------ 214 | try: 215 | if new_grid[count][abs(i-om[3])][j-om[3]]==0: 216 | new_grid[count][abs(i-om[3])][j-om[3]]=1 217 | except IndexError : 218 | pass 219 | 220 | # smer: ------------------------------------ drup ------ 221 | try: 222 | if new_grid[count][abs(i-om[2])][j+om[2]]==0: 223 | new_grid[count][abs(i-om[2])][j+om[2]]=1 224 | except IndexError : 225 | pass 226 | # smer: --------------------------------- dldown ------ 227 | try: 228 | if new_grid[count][i+om[2]][abs(j-om[2])]==0: 229 | new_grid[count][i+om[2]][abs(j-om[2])]=1 230 | except IndexError : 231 | pass 232 | # smer: --------------------------------- drdown ------ 233 | try: 234 | if new_grid[count][i+om[3]][j+om[3]]==0: 235 | new_grid[count][i+om[3]][j+om[3]]=1 236 | except IndexError : 237 | pass 238 | """ 239 | 240 | old_grid[count]=new_grid[count].copy() 241 | return old_grid[count] 242 | 243 | 244 | """ 245 | def Growth_2D(count): 246 | global old_grid, new_grid 247 | 248 | for i in range(N): 249 | for j in range(M): 250 | if old_grid[count][i][j]==1 and taula[i][j]==0 and total_matrix[i][j]<2: 251 | new_grid[count][i][j]=1 252 | try: 253 | if new_grid[count][i][j+1]==0: 254 | new_grid[count][i][j+1]= 1 255 | except IndexError: 256 | pass 257 | try: 258 | if new_grid[count][i][abs(j-1)]==0: 259 | new_grid[count][i][abs(j-1)]= 1 260 | except IndexError : 261 | pass 262 | try: 263 | if new_grid[count][i+1][j]==0: 264 | new_grid[count][i+1][j]=1 265 | except IndexError : 266 | pass 267 | try: 268 | if new_grid[count][abs(i-1)][j]==0: 269 | new_grid[count][abs(i-1)][j]=1 270 | except IndexError : 271 | pass 272 | 273 | old_grid[count]=new_grid[count].copy() 274 | return old_grid[count] 275 | """ 276 | 277 | """ ------------------------------------------------------------------------------------------------------------""" 278 | def show_vg(dT_field): # it shows the interface growth rate (vg)vs. undercooling temperatures (dT_field)at given time step 279 | vg=2.03e-4 * dT_field**2 - 0.544e-4 * dT_field 280 | plt.clf() 281 | plt.imshow(vg, extent=(np.amin(xim), np.amax(xim), np.amin(yim), np.amax(yim)), cmap=plt.get_cmap('rainbow'), interpolation='bessel') 282 | #plt.plot(dT_field[1], vg[1]) 283 | #print('dT= ',dT_field[1][6],'vg= ',vg[1][6]) 284 | return vg 285 | 286 | def get_growth_length(dT_field, cas): 287 | vg=2.03e-4 * dT_field**2 - 0.544e-4 * dT_field 288 | length= vg*cas 289 | return length 290 | """ -----------------------------------------------------------------------------------------------------------""" 291 | 292 | def vsota(nuk_rate, om): 293 | global total_matrix 294 | plt.clf() 295 | """ Commenting cancels the grain-growth and only formation of nuclei is observed""" 296 | for i in range(nuk_rate): 297 | Growth(i, om) 298 | 299 | total_matrix=sum(old_grid[i] for i in range(nuk_rate)) 300 | plt.imshow(total_matrix) 301 | 302 | 303 | tt=-1 304 | def animate(i): 305 | global tt 306 | tt +=1 307 | plt.clf() 308 | try: 309 | #T=Matrix_3D[tt] 310 | T = np.load('salome_'+str(tt)+'.npy') 311 | taljenje(T, Tmelt) 312 | plt.imshow(taula) 313 | """ 314 | dTt = T - Tmelt # termično podhlajanje, kjer je T iz Abaqus-a uvožena matrika dejanskih temperatur posamezne celice 315 | nuk_matrix_pov=nukleusi_pov(dTt) 316 | nuk_matrix_vol=nukleusi_vol(dTt) 317 | show_nuclei(nuk_matrix_pov, nuk_matrix_vol, tt) 318 | """ 319 | #show_vg(dTt) 320 | #dolzine=get_growth_length(dTt,1) 321 | #print(dolzine[0]) 322 | """ 323 | nuks=len(old_grid) 324 | vsota(nuks) 325 | """ 326 | #for i in range(N): 327 | #for j in range(M): 328 | # if old_grid[i][j]==1: 329 | #print(dolzine[i][j], tt) 330 | except IndexError: 331 | print('Done..') 332 | ani.event_source.stop() 333 | 334 | # Odkomentiraj spodnje 4 vrstice, če želiš pognati animacija_sledi 335 | """ 336 | time_frames = time_frames 337 | temp=np.zeros((2,N,M)) # talina 338 | haz=np.zeros((2,N,M)) # talina +h.a.z. (heat affected zone) 339 | out=np.zeros((2,N,M)) # talina + sled 340 | """ 341 | 342 | tt=0 343 | def animacija_sledi(i): 344 | global tt 345 | tt+=1 346 | #print('---------------- frame number: ',tt,' -----------------') 347 | if tt 0: 12 | item = random.choice(x) 13 | x=np.delete(x,np.where(x==item)) 14 | else: 15 | item = x[0] 16 | x=np.delete(x,np.where(x==item)) 17 | return x 18 | 19 | def merging(prva,druga): 20 | tot = np.where(druga==0, prva, druga) 21 | return tot 22 | 23 | def W(O, L): 24 | O = np.array(O) 25 | cos_Z = np.dot(O[0], L) / (np.linalg.norm(O[0]* np.linalg.norm(L))) 26 | cos_X = np.dot(O[1], L) / (np.linalg.norm(O[1] * np.linalg.norm(L))) 27 | cos_Y = np.dot(O[2], L) / (np.linalg.norm(O[2] * np.linalg.norm(L))) 28 | return np.max(np.absolute(np.array([cos_Z, cos_X, cos_Y]))) 29 | 30 | 31 | '''[001]''' 32 | def pad001(zrnec):pad001=(np.pad(faza,((0,0),(0,0), (1,0)), 'constant')[:,:,:-1]==zrnec);return pad001 33 | def pad00_1(zrnec):pad00_1=(np.pad(faza,((0,0),(0,0), (0,1)), 'constant')[:,:,1:]==zrnec); return pad00_1 34 | 35 | '''[010]''' 36 | def pad010(zrnec):pad010=(np.pad(faza,((0,0),(1,0), (0,0)), 'constant')[:,:-1,:]==zrnec);return pad010 37 | def pad0_10(zrnec):pad0_10=(np.pad(faza,((0,0),(0,1), (0,0)), 'constant')[:,1:,:]==zrnec);return pad0_10 38 | 39 | '''[011]''' 40 | def pad011(zrnec):pad011=(np.pad(faza,((0,0),(1,0), (1,0)), 'constant')[:,:-1,:-1]==zrnec); return pad011 41 | def pad01_1(zrnec):pad01_1=(np.pad(faza,((0,0),(1,0), (0,1)), 'constant')[:,:-1,1:]==zrnec);return pad01_1 42 | def pad0_11(zrnec):pad0_11=(np.pad(faza,((0,0),(0,1), (1,0)), 'constant')[:,1:,:-1]==zrnec); return pad0_11 43 | def pad0_1_1(zrnec):pad0_1_1=(np.pad(faza,((0,0),(0,1), (0,1)), 'constant')[:,1:,1:]==zrnec); return pad0_1_1 44 | 45 | '''[002]''' 46 | def pad002(zrnec):pad002=(np.pad(faza,((0,0),(0,0), (2,0)), 'constant')[:,:,:-2]==zrnec); return pad002 47 | def pad00_2(zrnec):pad00_2=(np.pad(faza,((0,0),(0,0), (0,2)), 'constant')[:,:,2:]==zrnec); return pad00_2 48 | 49 | '''[020]''' 50 | def pad020(zrnec):pad020=(np.pad(faza,((0,0),(2,0), (0,0)), 'constant')[:,:-2,:]==zrnec); return pad020 51 | def pad0_20(zrnec):pad0_20=(np.pad(faza,((0,0),(0,2), (0,0)), 'constant')[:,2:,:]==zrnec); return pad0_20 52 | 53 | '''[012]''' 54 | def pad012(zrnec):pad012=(np.pad(faza,((0,0),(1,0), (2,0)), 'constant')[:,:-1,:-2]==zrnec); return pad012 55 | def pad01_2(zrnec):pad01_2=(np.pad(faza,((0,0),(1,0), (0,2)), 'constant')[:,:-1,2:]==zrnec);return pad01_2 56 | def pad0_12(zrnec):pad0_12=(np.pad(faza,((0,0),(0,1), (2,0)), 'constant')[:,1:,:-2]==zrnec);return pad0_12 57 | def pad0_1_2(zrnec):pad0_1_2=(np.pad(faza,((0,0),(0,1), (0,2)), 'constant')[:,1:,2:]==zrnec);return pad0_1_2 58 | 59 | '''[021]''' 60 | def pad021(zrnec):pad021=(np.pad(faza,((0,0),(2,0), (1,0)), 'constant')[:,:-2,:-1]==zrnec);return pad021 61 | def pad02_1(zrnec):pad02_1=(np.pad(faza,((0,0),(2,0), (0,1)), 'constant')[:,:-2,1:]==zrnec);return pad02_1 62 | def pad0_21(zrnec):pad0_21=(np.pad(faza,((0,0),(0,2), (1,0)), 'constant')[:,2:,:-1]==zrnec);return pad0_21 63 | def pad0_2_1(zrnec):pad0_2_1=(np.pad(faza,((0,0),(0,2), (0,1)), 'constant')[:,2:,1:]==zrnec);return pad0_2_1 64 | 65 | '''[022]''' 66 | def pad022(zrnec):pad022=(np.pad(faza,((0,0),(2,0), (2,0)), 'constant')[:,:-2,:-2]==zrnec);return pad022 67 | def pad02_2(zrnec):pad02_2=(np.pad(faza,((0,0),(2,0), (0,2)), 'constant')[:,:-2,2:]==zrnec);return pad02_2 68 | def pad0_22(zrnec):pad0_22=(np.pad(faza,((0,0),(0,2), (2,0)), 'constant')[:,2:,:-2]==zrnec);return pad0_22 69 | def pad0_2_2(zrnec):pad0_2_2=(np.pad(faza,((0,0),(0,2), (0,2)), 'constant')[:,2:,2:]==zrnec);return pad0_2_2 70 | 71 | '''[030]''' 72 | def pad030(zrnec):pad030=(np.pad(faza,((0,0),(3,0), (0,0)), 'constant')[:,:-3,:]==zrnec);return pad030 73 | def pad0_30(zrnec):pad0_30=(np.pad(faza,((0,0),(0,3), (0,0)), 'constant')[:,3:,:]==zrnec);return pad0_30 74 | 75 | '''[013]''' 76 | def pad013(zrnec):pad013=(np.pad(faza,((0,0),(1,0), (3,0)), 'constant')[:,:-1,:-3]==zrnec);return pad013 77 | def pad01_3(zrnec):pad01_3=(np.pad(faza,((0,0),(1,0), (0,3)), 'constant')[:,:-1,3:]==zrnec);return pad01_3 78 | def pad0_13(zrnec):pad0_13=(np.pad(faza,((0,0),(0,1), (3,0)), 'constant')[:,1:,:-3]==zrnec);return pad0_13 79 | def pad0_1_3(zrnec):pad0_1_3=(np.pad(faza,((0,0),(0,1), (0,3)), 'constant')[:,1:,3:]==zrnec);return pad0_1_3 80 | 81 | '''[031]''' 82 | def pad031(zrnec):pad031=(np.pad(faza,((0,0),(3,0), (1,0)), 'constant')[:,:-3,:-1]==zrnec);return pad031 83 | def pad03_1(zrnec):pad03_1=(np.pad(faza,((0,0),(3,0), (0,1)), 'constant')[:,:-3,1:]==zrnec);return pad03_1 84 | def pad0_31(zrnec):pad0_31=(np.pad(faza,((0,0),(0,3), (1,0)), 'constant')[:,3:,:-1]==zrnec);return pad0_31 85 | def pad0_3_1(zrnec):pad0_3_1=(np.pad(faza,((0,0),(0,3), (0,1)), 'constant')[:,3:,1:]==zrnec);return pad0_3_1 86 | 87 | 88 | def Dsr_1st(r): 89 | if random_distances: 90 | cell_1st = cell * (0.5 + 1.158*r) #"""------------------1st shell ::: [001], [010], [100] ::: 6 neighbours ------------------""" 91 | else: 92 | cell_1st=cell 93 | return cell_1st 94 | 95 | def Dsr_5th(r): 96 | if random_distances: 97 | cell_5th=cell*(1.5 + 1.098*r) #''' ------------------5th shell ::: [002], [020], [200] ::: 6 neighbours ------------------ ''' 98 | else: 99 | cell_5th=cell*2 100 | return cell_5th 101 | 102 | 103 | Z=1 104 | X=11 105 | Y=11 106 | 107 | faza = np.zeros((Z,X,Y)) 108 | taula = np.zeros((Z,X,Y)) 109 | likvid = np.zeros((Z,X,Y)) 110 | cas = np.zeros((Z,X,Y)) # časovna matrika 111 | vg = np.zeros((Z,X,Y)) # matrika hitrosti rasti 112 | vg = 1 # Value of homogeneous 'growing velocity' field, a.u., for testing and code development 113 | 114 | 115 | random_distances = False; R=None 116 | 117 | cell=1 # for mesh dependency development (MDD) 118 | dt=cell/6 119 | 120 | Negatives = {-1:0}; asc = {}; grain_counter = 0; S = {}; np.random.seed(75689803) 121 | M = { 1: {'ß':(0, 5, 5)}, 122 | 2: {'ß':(0, 6, 6)}, 123 | } 124 | for i in M: 125 | faza[M[i]['ß'][0],M[i]['ß'][1],M[i]['ß'][2]]=i # define nucleus ID in faza matrix 126 | asc[i] = str(i) 127 | 128 | grain_ID = np.array(list(asc.keys())) 129 | cas[np.isin(faza, grain_ID, invert=False)] = -1 130 | taula=0;likvid=0; grain_counter=len(grain_ID) 131 | 132 | 133 | 134 | smeri = np.array(['001', '00_1', '010', '0_10', '002', '00_2', '020', '0_20', ]) 135 | #smeri = np.array(['001', '002']) 136 | 137 | '''**************************''' 138 | START_step = 0 # Starting time step number 139 | END_step = 14 # Ending time step number 140 | '''**************************''' 141 | 142 | for i in range(START_step, END_step): 143 | for negind in Negatives: 144 | time_counter(negind) 145 | 146 | for s in smeri[:]: 147 | for negind in Negatives: 148 | ''' ----------------------------------------- 1st shell -------------------> 6 nearest neighbours ''' 149 | if s == '001': 150 | if negind == -1 and i==START_step: 151 | cas001 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(cas,((0,0),(0,0), (1,0)), 'constant')[:,:,:-1]==negind), Negatives[negind], cas) 152 | S[s]=cas001; del cas001 153 | else: 154 | cas001 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(S[s],((0,0),(0,0), (1,0)), 'constant')[:,:,:-1]==negind), Negatives[negind], S[s]) 155 | S[s]=cas001; del cas001 156 | 157 | elif s == '00_1': 158 | if negind == -1 and i==START_step: 159 | cas00_1 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(cas,((0,0),(0,0), (0,1)), 'constant')[:,:,1:]==negind), Negatives[negind], cas) 160 | S[s]=cas00_1; del cas00_1 161 | else: 162 | cas00_1 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(S[s],((0,0),(0,0), (0,1)), 'constant')[:,:,1:]==negind), Negatives[negind], S[s]) 163 | S[s]=cas00_1; del cas00_1 164 | 165 | elif s == '010': 166 | if negind == -1 and i==START_step: 167 | cas010 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(cas,((0,0),(1,0), (0,0)), 'constant')[:,:-1,:]==negind), Negatives[negind], cas) 168 | S[s]=cas010; del cas010 169 | else: 170 | cas010 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(S[s],((0,0),(1,0), (0,0)), 'constant')[:,:-1,:]==negind), Negatives[negind], S[s]) 171 | S[s]=cas010; del cas010 172 | 173 | elif s == '0_10': 174 | if negind == -1 and i==START_step: 175 | cas0_10 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(cas,((0,0),(0,1), (0,0)), 'constant')[:,1:,:]==negind), Negatives[negind], cas) 176 | S[s]=cas0_10; del cas0_10 177 | else: 178 | cas0_10 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(S[s],((0,0),(0,1), (0,0)), 'constant')[:,1:,:]==negind), Negatives[negind], S[s]) 179 | S[s]=cas0_10; del cas0_10 180 | 181 | elif s == '002': 182 | if negind == -1 and i==START_step: 183 | cas002 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(cas,((0,0),(0,0), (2,0)), 'constant')[:,:,:-2]==negind), Negatives[negind], cas) 184 | S[s]=cas002; del cas002 185 | else: 186 | cas002 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(S[s],((0,0),(0,0), (2,0)), 'constant')[:,:,:-2]==negind), Negatives[negind], S[s]) 187 | S[s]=cas002; del cas002 188 | 189 | elif s == '00_2': 190 | if negind == -1 and i==START_step: 191 | cas00_2 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(cas,((0,0),(0,0), (0,2)), 'constant')[:,:,2:]==negind), Negatives[negind], cas) 192 | S[s]=cas00_2; del cas00_2 193 | else: 194 | cas00_2 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(S[s],((0,0),(0,0), (0,2)), 'constant')[:,:,2:]==negind), Negatives[negind], S[s]) 195 | S[s]=cas00_2; del cas00_2 196 | 197 | elif s == '020': 198 | if negind == -1 and i==START_step: 199 | cas020 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(cas,((0,0),(2,0), (0,0)), 'constant')[:,:-2,:]==negind), Negatives[negind], cas) 200 | S[s]=cas020; del cas020 201 | else: 202 | cas020 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(S[s],((0,0),(2,0), (0,0)), 'constant')[:,:-2,:]==negind), Negatives[negind], S[s]) 203 | S[s]=cas020; del cas020 204 | 205 | elif s == '0_20': 206 | if negind == -1 and i==START_step: 207 | cas0_20 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(cas,((0,0),(0,2), (0,0)), 'constant')[:,2:,:]==negind), Negatives[negind], cas) 208 | S[s]=cas0_20; del cas0_20 209 | else: 210 | cas0_20 = np.where((np.isin(faza, grain_ID, invert=True)) & (np.pad(S[s],((0,0),(0,2), (0,0)), 'constant')[:,2:,:]==negind), Negatives[negind], S[s]) 211 | S[s]=cas0_20; del cas0_20 212 | 213 | 214 | F = faza.copy() 215 | for g in grain_ID: 216 | grain_ID = random_selection(grain_ID) 217 | grain = item 218 | directions = smeri.copy() 219 | seznam_premikov = [] 220 | for d in directions: 221 | directions = random_selection(directions) 222 | s = item 223 | 224 | ''' ----------------------------------------- 1st shell -------------------> 6 nearest neighbours ''' 225 | if s == '001': 226 | dij = np.array([0,0,1]) 227 | lij = vg*S[s] 228 | faza001 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_1st(R) )&(np.pad(faza,((0,0),(0,0), (1,0)), 'constant')[:,:,:-1]==grain), grain, faza) 229 | seznam_premikov.append(faza001); del faza001 230 | 231 | elif s == '00_1': 232 | dij = np.array([0,0,-1]) 233 | lij = vg*S[s] 234 | faza00_1 = np.where((faza==0)& (taula==0)& (likvid==0)& (lij>=Dsr_1st(R) )&(np.pad(faza,((0,0),(0,0), (0,1)), 'constant')[:,:,1:]==grain), grain, faza) 235 | seznam_premikov.append(faza00_1); del faza00_1 236 | 237 | elif s == '010': 238 | dij = np.array([0,1,0]) 239 | lij = vg*S[s] 240 | faza010 = np.where((faza==0)& (taula==0)& (likvid==0)&(lij>=Dsr_1st(R) )&(np.pad(faza,((0,0),(1,0), (0,0)), 'constant')[:,:-1,:]==grain), grain, faza) 241 | seznam_premikov.append(faza010); del faza010 242 | 243 | elif s == '0_10': 244 | dij = np.array([0,-1,0]) 245 | lij = vg*S[s] 246 | faza0_10 = np.where((faza==0)& (taula==0)& (likvid==0)&(lij>=Dsr_1st(R) )&(np.pad(faza,((0,0),(0,1), (0,0)), 'constant')[:,1:,:]==grain), grain, faza) 247 | seznam_premikov.append(faza0_10); del faza0_10 248 | 249 | elif s == '002': 250 | dij = np.array([0,0,2]) 251 | lij = vg*S[s] 252 | faza002 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_5th(R) ) 253 | &(np.pad(faza,((0,0),(0,0), (2,0)), 'constant')[:,:,:-2]==grain) 254 | & ((np.pad(faza,((0,0),(0,0), (1,0)), 'constant')[:,:,:-1]==grain) # 001 255 | | (np.pad(faza,((0,0),(1,0), (1,0)), 'constant')[:,:-1,:-1]==grain) # 011 256 | | (np.pad(faza,((0,0),(0,1), (1,0)), 'constant')[:,1:,:-1]==grain) # 0_11 257 | | (np.pad(faza,((0,0),(1,0), (2,0)), 'constant')[:,:-1,:-2]==grain) # 012 258 | | (np.pad(faza,((0,0),(0,1), (2,0)), 'constant')[:,1:,:-2]==grain)) # 0_12 259 | , grain, faza) 260 | seznam_premikov.append(faza002); del faza002 261 | 262 | elif s == '00_2': 263 | dij = np.array([0,0,-2]) 264 | lij = vg*S[s] 265 | faza00_2 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_5th(R) ) 266 | &(np.pad(faza,((0,0),(0,0), (0,2)), 'constant')[:,:,2:]==grain) 267 | & ((np.pad(faza,((0,0),(0,0), (0,1)), 'constant')[:,:,1:]==grain) # 00_1 268 | | (np.pad(faza,((0,0),(1,0), (0,1)), 'constant')[:,:-1,1:]==grain) # 01_1 269 | | (np.pad(faza,((0,0),(0,1), (0,1)), 'constant')[:,1:,1:]==grain) # 0_1_1 270 | | (np.pad(faza,((0,0),(1,0), (0,2)), 'constant')[:,:-1,2:]==grain) # 01_2 271 | | (np.pad(faza,((0,0),(0,1), (0,2)), 'constant')[:,1:,2:]==grain)) # 0_1_2 272 | , grain, faza) 273 | seznam_premikov.append(faza00_2); del faza00_2 274 | 275 | elif s == '020': 276 | dij = np.array([0,2,0]) 277 | lij = vg*S[s] 278 | faza020 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_5th(R) ) 279 | &(np.pad(faza,((0,0),(2,0), (0,0)), 'constant')[:,:-2,:]==grain) 280 | & ((np.pad(faza,((0,0),(1,0), (0,0)), 'constant')[:,:-1,:]==grain) # 010 281 | | (np.pad(faza,((0,0),(1,0), (1,0)), 'constant')[:,:-1,:-1]==grain) # 011 282 | | (np.pad(faza,((0,0),(1,0), (0,1)), 'constant')[:,:-1,1:]==grain) # 01_1 283 | | (np.pad(faza,((0,0),(2,0), (1,0)), 'constant')[:,:-2,:-1]==grain) # 021 284 | | (np.pad(faza,((0,0),(2,0), (0,1)), 'constant')[:,:-2,1:]==grain)) # 02_1 285 | , grain, faza) 286 | seznam_premikov.append(faza020); del faza020 287 | 288 | elif s == '0_20': 289 | dij = np.array([0,-2,0]) 290 | lij = vg*S[s] 291 | faza0_20 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_5th(R) ) 292 | &(np.pad(faza,((0,0),(0,2), (0,0)), 'constant')[:,2:,:]==grain) 293 | & ((np.pad(faza,((0,0),(0,1), (0,0)), 'constant')[:,1:,:]==grain) # 0_10 294 | | (np.pad(faza,((0,0),(0,1), (1,0)), 'constant')[:,1:,:-1]==grain) # 0_11 295 | | (np.pad(faza,((0,0),(0,1), (0,1)), 'constant')[:,1:,1:]==grain) # 0_1_1 296 | | (np.pad(faza,((0,0),(0,2), (1,0)), 'constant')[:,2:,:-1]==grain) # 0_21 297 | | (np.pad(faza,((0,0),(0,2), (0,1)), 'constant')[:,2:,1:]==grain)) # 0_2_1 298 | , grain, faza) 299 | seznam_premikov.append(faza0_20); del faza0_20 300 | 301 | 302 | total=merging(seznam_premikov[0], seznam_premikov[1]) 303 | 304 | if len(smeri)> 2: 305 | for move in range(2, len(smeri)): 306 | total=merging(total, seznam_premikov[move]) 307 | 308 | faza = total.copy() 309 | 310 | grain_ID = np.array(list(asc.keys())) 311 | 312 | if not np.all(faza==F): 313 | negind -=1 314 | for s in S: 315 | S[s][np.isin(faza-F, grain_ID)]= negind 316 | Negatives[negind]=0 317 | 318 | times = np.array(list(S.values())) 319 | cas_total = merging(times[0], times[1]) 320 | if len(smeri)> 2: 321 | for move in range(2, len(smeri)): 322 | cas_total = merging(cas_total, times[move]) 323 | 324 | try: 325 | cas = cas_total.copy() 326 | except NameError: 327 | pass 328 | 329 | 330 | 331 | 332 | plt.imshow(faza[0]) 333 | plt.figure(); plt.imshow(cas[0]) 334 | 335 | 336 | 337 | """ 338 | '''........................................ [012], [021] families ::: Dsr_4th(R) ::: ......................................... 8 neighbours ''' 339 | 340 | faza012 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_4th(R) )& pad012(grain) 341 | &(pad001 (grain)| pad011 (grain)| pad002 (grain)| pad021 (grain)| pad022(grain)), grain, faza) 342 | 343 | faza01_2 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_4th(R) )& pad01_2(grain) 344 | & (pad00_1(grain) | pad01_1(grain) | pad00_2(grain) | pad02_1(grain) | pad02_2(grain)), grain, faza) 345 | 346 | faza0_12 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_4th(R) )& pad0_12(grain) 347 | & (pad001(grain) | pad0_11(grain) | pad002(grain) | pad0_21(grain) | pad0_22(grain)), grain, faza) 348 | 349 | faza0_1_2 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_4th(R) )& pad0_1_2(grain) 350 | & (pad00_1(grain) | pad0_1_1(grain) | pad00_2(grain) | pad0_2_1(grain) | pad0_2_2(grain)), grain, faza) 351 | 352 | 353 | faza021 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_4th(R) )& pad021(grain) 354 | & (pad010(grain) | pad011(grain) | pad020(grain) | pad030(grain) | pad012(grain)), grain, faza) 355 | 356 | faza02_1 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_4th(R) )& pad02_1(grain) 357 | & (pad010(grain) | pad01_1(grain) | pad020(grain) | pad030(grain) | pad01_2(grain)), grain, faza) 358 | 359 | faza0_21 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_4th(R) )& pad0_21(grain) 360 | & (pad0_10(grain) | pad0_11(grain) | pad0_20(grain) | pad0_30(grain) | pad0_12(grain)), grain, faza) 361 | 362 | faza0_2_1 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_4th(R) )& pad0_2_1(grain) 363 | & (pad0_10(grain) | pad0_1_1(grain) | pad0_20(grain) | pad0_30(grain) | pad0_1_2(grain)), grain, faza) 364 | 365 | ''' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~''' 366 | 367 | 368 | '''........................................ [002], [020] families ::: Dsr_5th(R) ::: ......................................... 4 neighbours ''' 369 | 370 | faza002 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_5th(R) )& pad002(grain) 371 | & (pad001(grain) | pad011(grain) | pad0_11(grain) | pad012(grain) | pad0_12(grain)), grain, faza) 372 | 373 | faza00_2 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_5th(R) )& pad00_2(grain) 374 | & (pad00_1(grain) | pad01_1(grain) | pad0_1_1(grain) | pad01_2(grain) | pad0_1_2(grain)), grain, faza) 375 | 376 | faza020 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_5th(R) )& pad020(grain) 377 | & (pad010(grain) | pad011(grain) | pad01_1(grain) | pad021(grain) | pad02_1(grain)), grain, faza) 378 | 379 | faza0_20 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_5th(R) )& pad0_20(grain) 380 | & (pad0_10(grain) | pad0_11(grain) | pad0_1_1(grain) | pad0_21(grain) | pad0_2_1(grain)), grain, faza) ) 381 | 382 | '''~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~''' 383 | 384 | 385 | '''................................................ [022] family ::: Dsr_6th(R) ::: .................................................... 4 neighbours ''' 386 | 387 | faza022 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_6th(R) )& pad022(grain) 388 | & (pad012(grain) | pad011(grain) | pad021(grain) | pad013(grain) | pad031(grain)), grain, faza) 389 | 390 | faza02_2 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_6th(R) )& pad02_2(grain) 391 | & (pad01_2(grain) | pad01_1(grain) | pad02_1(grain) | pad01_3(grain) | pad03_1(grain)) , grain, faza) 392 | 393 | faza0_22 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_6th(R) )& pad0_22(grain) 394 | & (pad0_12(grain) | pad0_11(grain) | pad0_21(grain) | pad0_13(grain) | pad0_31(grain)), grain, faza) 395 | 396 | faza0_2_2 = np.where((faza==0)& (taula==0)& (likvid==0) &(lij>=Dsr_6th(R) )& pad0_2_2(grain) 397 | & (pad0_1_2(grain) | pad0_1_1(grain) | pad0_2_1(grain) | pad0_1_3(grain) | pad0_3_1(grain)), grain, faza) 398 | 399 | '''~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~''' 400 | 401 | """ 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | --------------------------------------------------------------------------------