Module CreateIC
@author: Alexandre Sac–Morane alexandre.sac-morane@uclouvain.be
This is the file where the initial conditions are defined.
Expand source code
#-------------------------------------------------------------------------------
# Librairies
#-------------------------------------------------------------------------------
import numpy as np
import matplotlib.pyplot as plt
import random
import math
import skfmm
from scipy import ndimage
#-------------------------------------------------------------------------------
# Functions
#-------------------------------------------------------------------------------
def check_overlap(L_radius_grains, L_pos_grains, L_radius_grains_virtual, L_pos_grains_virtual, L_i_grain_virtual, factor_int):
'''
Determine if grains are overlapping.
Used in Insert_Grains() function.
'''
overlap = False
# real - real
L_overlap = []
for i_g in range(len(L_radius_grains)-1):
# radius of grains
radius_i = L_radius_grains[i_g]
# position of grains
pos_i = L_pos_grains[i_g]
for j_g in range(i_g+1, len(L_radius_grains)):
# radius of grains
radius_j = L_radius_grains[j_g]
# position of grains
pos_j = L_pos_grains[j_g]
# check distance
if np.linalg.norm(pos_i-pos_j) < radius_i+radius_j+factor_int:
overlap = True
L_overlap.append((i_g, j_g))
# real - virtual
L_overlap_virtual = []
for i_g in range(len(L_radius_grains)):
# radius of grains
radius_i = L_radius_grains[i_g]
# position of grains
pos_i = L_pos_grains[i_g]
for j_g in range(len(L_radius_grains_virtual)):
# radius of grains
radius_j = L_radius_grains_virtual[j_g]
# position of grains
pos_j = L_pos_grains_virtual[j_g]
# check distance
if np.linalg.norm(pos_i-pos_j) < radius_i+radius_j+factor_int:
overlap = True
L_overlap_virtual.append((i_g, j_g, L_i_grain_virtual[j_g]))
return overlap, L_overlap, L_overlap_virtual
#-------------------------------------------------------------------------------
def compute_virtual(dict_user, L_pos_grains, L_radius_grains_step):
'''
Compute virtual grains with the periodic conditions.
'''
L_pos_grains_virtual = []
L_radius_grains_virtual = []
L_i_grain_virtual = []
for i_grain in range(len(L_pos_grains)):
per_x_p = False
per_x_m = False
per_y_p = False
per_y_m = False
# - x limit
if L_pos_grains[i_grain][0] < -dict_user['dim_domain']/2 + L_radius_grains_step[i_grain]:
L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([ dict_user['dim_domain'], 0]))
L_radius_grains_virtual.append(L_radius_grains_step[i_grain])
L_i_grain_virtual.append(i_grain)
per_x_m = True
# + x limit
if dict_user['dim_domain']/2 - L_radius_grains_step[i_grain] < L_pos_grains[i_grain][0]:
L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([-dict_user['dim_domain'], 0]))
L_radius_grains_virtual.append(L_radius_grains_step[i_grain])
L_i_grain_virtual.append(i_grain)
per_x_p = True
# - y limit
if L_pos_grains[i_grain][1] < -dict_user['dim_domain']/2 + L_radius_grains_step[i_grain]:
L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([0, dict_user['dim_domain']]))
L_radius_grains_virtual.append(L_radius_grains_step[i_grain])
L_i_grain_virtual.append(i_grain)
per_y_m = True
# + y limit
if dict_user['dim_domain']/2 - L_radius_grains_step[i_grain] < L_pos_grains[i_grain][1]:
L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([0, -dict_user['dim_domain']]))
L_radius_grains_virtual.append(L_radius_grains_step[i_grain])
L_i_grain_virtual.append(i_grain)
per_y_p = True
# - x and - y limits
if per_x_m and per_y_m:
L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([ dict_user['dim_domain'], dict_user['dim_domain']]))
L_radius_grains_virtual.append(L_radius_grains_step[i_grain])
L_i_grain_virtual.append(i_grain)
# - x and + y limits
if per_x_m and per_y_p:
L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([ dict_user['dim_domain'], -dict_user['dim_domain']]))
L_radius_grains_virtual.append(L_radius_grains_step[i_grain])
L_i_grain_virtual.append(i_grain)
# + x and - y limit
if per_x_p and per_y_m:
L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([ -dict_user['dim_domain'], dict_user['dim_domain']]))
L_radius_grains_virtual.append(L_radius_grains_step[i_grain])
L_i_grain_virtual.append(i_grain)
# + x and + y limit
if per_x_p and per_y_p:
L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([ -dict_user['dim_domain'], -dict_user['dim_domain']]))
L_radius_grains_virtual.append(L_radius_grains_step[i_grain])
L_i_grain_virtual.append(i_grain)
return L_pos_grains_virtual, L_radius_grains_virtual, L_i_grain_virtual
#-------------------------------------------------------------------------------
def Insert_One_Grain_Seed(dict_sample, dict_user):
'''
Insert one grain in the domain. The grain is circle defined by a radius.
Map of phi, psi and c are generated.
'''
# Initialize the arrays
M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh']))
M_phi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh']))
M_c = dict_user['C_eq_phi']*np.ones((dict_user['n_mesh'],dict_user['n_mesh']))
# Initialize the mesh lists
L_x = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh'])
L_y = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh'])
# compute m_H20_m_cement
M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh']))
# iterate on grains
x_grain = 0
y_grain = 0
Center_grain = np.array([x_grain, y_grain])
r_grain = dict_user['R']
# find the nearest node of the center
L_search = list(abs(np.array(L_x-x_grain)))
i_x_center = L_search.index(min(L_search))
L_search = list(abs(np.array(L_y-y_grain)))
i_y_center = L_search.index(min(L_search))
# compute the number of node (depending on the radius)
n_nodes = int(r_grain/(L_x[1]-L_x[0]))+4
for i_x in range(max(0,i_x_center-n_nodes),min(i_x_center+n_nodes+1,len(L_x))):
for i_y in range(max(0,i_y_center-n_nodes),min(i_y_center+n_nodes+1,len(L_y))):
x = L_x[i_x]
y = L_y[i_y]
Point = np.array([x, y])
distance = np.linalg.norm(Point-Center_grain)
# Update map psi
if M_psi[-1-i_y, i_x] == 0 : # do not erase data already written
if distance <= r_grain:
M_psi[-1-i_y, i_x] = 1
elif distance >= r_grain:
M_psi[-1-i_y, i_x] = 0
# compute surface grains and water
Surface_grain = np.sum(M_psi)/M_psi.size*dict_user['dim_domain']*dict_user['dim_domain']
Surface_water = dict_user['dim_domain']*dict_user['dim_domain'] - Surface_grain
# compute ratio
m_H20_m_cement = (Surface_water*dict_user['rho_water'])/(Surface_grain*dict_user['rho_g'])
# print result
print()
print('m_H20/m_cement:', round(m_H20_m_cement,2),'targetted')
# Compute phi
n_seed = dict_user['n_seed']
for i_seed in range(n_seed):
i_try = 0
seed_created = False
while not seed_created and i_try < 100:
i_try = i_try + 1
# generate a seed
i_x_seed = random.randint(0, len(L_x)-1)
i_y_seed = random.randint(0, len(L_y)-1)
center_seed = np.array([L_x[i_x_seed], L_y[i_y_seed]])
# verify the node is not in a cement source
if M_psi[-1-i_y_seed, i_x_seed] != 1:
seed_created = True
# generate the seed
r_seed = 1.5*dict_user['w_int']
# compute the number of node (depending on the radius)
n_nodes = int(r_seed/(L_x[1]-L_x[0]))+4
for i_x in range(max(0,i_x_seed-n_nodes),min(i_x_seed+n_nodes+1,len(L_x))):
for i_y in range(max(0,i_y_seed-n_nodes),min(i_y_seed+n_nodes+1,len(L_y))):
x = L_x[i_x]
y = L_y[i_y]
Point = np.array([x, y])
distance = np.linalg.norm(Point-center_seed)
# Update map psi
if M_phi[-1-i_y, i_x] == 0 : # do not erase data already written
if distance <= r_seed:
M_phi[-1-i_y, i_x] = 1
elif distance >= r_seed:
M_phi[-1-i_y, i_x] = 0
# print psi/phi map
M_phi_psi = M_psi + 2*M_phi
fig, (ax1) = plt.subplots(1,1,figsize=(16,9))
title_fontsize = 30
im = ax1.imshow(M_phi_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]), vmax=2)
cbar = fig.colorbar(im, ax=ax1)
cbar.set_ticks(ticks=[0, 1, 2], labels=['Pore', 'Source', 'C-S-H'])
fig.tight_layout()
fig.savefig('png/IC_one_map.png')
plt.close(fig)
# adapt maps
M_psi = M_psi - 0.5
M_phi = M_phi - 0.5
# compute the signed distance functions
sd_phi = skfmm.distance(M_phi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]]))
sd_psi = skfmm.distance(M_psi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]]))
# compute the phase field variables
for i_x in range(len(L_x)):
for i_y in range(len(L_y)):
# phi
if sd_phi[i_y, i_x] > dict_user['w_int']/2: # inside the grain
M_phi[i_y, i_x] = 1
elif sd_phi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain
M_phi[i_y, i_x] = 0
else : # in the interface
M_phi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_phi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int'])))
# psi
if sd_psi[i_y, i_x] > dict_user['w_int']/2: # inside the grain
M_psi[i_y, i_x] = 1
elif sd_psi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain
M_psi[i_y, i_x] = 0
else : # in the interface
M_psi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_psi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int'])))
# result
print()
print('Mean value of psi:', round(np.sum(M_psi)/M_psi.size,2))
print('Mean value of phi:', round(np.sum(M_phi)/M_phi.size,2))
# Plot maps
fig, ((ax1),(ax2),(ax3)) = plt.subplots(3,1,figsize=(9,25))
# parameters
title_fontsize = 30
# psi
im = ax1.imshow(M_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax1)
ax1.set_title(r'Map of $\psi$',fontsize = title_fontsize)
# phi
im = ax2.imshow(M_phi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax2)
ax2.set_title(r'Map of $\phi$',fontsize = title_fontsize)
# c
im = ax3.imshow(M_c, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax3)
ax3.set_title(r'Map of c',fontsize = title_fontsize)
fig.savefig('png/IC.png')
plt.close(fig)
# save in dicts
dict_sample['L_x'] = L_x
dict_sample['L_y'] = L_y
dict_sample['M_psi'] = M_psi
dict_sample['M_phi'] = M_phi
dict_sample['M_c'] = M_c
# Write data
file_to_write_psi = open('txt/psi.txt','w')
file_to_write_phi = open('txt/phi.txt','w')
file_to_write_c = open('txt/c.txt','w')
# x
file_to_write_psi.write('AXIS X\n')
file_to_write_phi.write('AXIS X\n')
file_to_write_c.write('AXIS X\n')
line = ''
for x in dict_sample['L_x']:
line = line + str(x)+ ' '
line = line + '\n'
file_to_write_psi.write(line)
file_to_write_phi.write(line)
file_to_write_c.write(line)
# y
file_to_write_psi.write('AXIS Y\n')
file_to_write_phi.write('AXIS Y\n')
file_to_write_c.write('AXIS Y\n')
line = ''
for y in dict_sample['L_y']:
line = line + str(y)+ ' '
line = line + '\n'
file_to_write_psi.write(line)
file_to_write_phi.write(line)
file_to_write_c.write(line)
# data
file_to_write_psi.write('DATA\n')
file_to_write_phi.write('DATA\n')
file_to_write_c.write('DATA\n')
for l in range(len(dict_sample['L_y'])):
for c in range(len(dict_sample['L_x'])):
file_to_write_psi.write(str(M_psi[-1-l][c])+'\n')
file_to_write_phi.write(str(M_phi[-1-l][c])+'\n')
file_to_write_c.write(str(M_c[-1-l][c])+'\n')
# close
file_to_write_psi.close()
file_to_write_phi.close()
file_to_write_c.close()
#-------------------------------------------------------------------------------
def Insert_One_Grain_Seed_Fixed(dict_sample, dict_user):
'''
Insert one grain in the domain. The grain is circle defined by a radius.
Map of phi, psi and c are generated.
'''
# Initialize the arrays
M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh']))
M_phi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh']))
M_c = dict_user['C_eq_phi']*np.ones((dict_user['n_mesh'],dict_user['n_mesh']))
# Initialize the mesh lists
L_x = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh'])
L_y = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh'])
# compute m_H20_m_cement
M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh']))
# iterate on grains
x_grain = 0
y_grain = 0
Center_grain = np.array([x_grain, y_grain])
r_grain = dict_user['R']
# find the nearest node of the center
L_search = list(abs(np.array(L_x-x_grain)))
i_x_center = L_search.index(min(L_search))
L_search = list(abs(np.array(L_y-y_grain)))
i_y_center = L_search.index(min(L_search))
# compute the number of node (depending on the radius)
n_nodes = int(r_grain/(L_x[1]-L_x[0]))+4
for i_x in range(max(0,i_x_center-n_nodes),min(i_x_center+n_nodes+1,len(L_x))):
for i_y in range(max(0,i_y_center-n_nodes),min(i_y_center+n_nodes+1,len(L_y))):
x = L_x[i_x]
y = L_y[i_y]
Point = np.array([x, y])
distance = np.linalg.norm(Point-Center_grain)
# Update map psi
if M_psi[-1-i_y, i_x] == 0 : # do not erase data already written
if distance <= r_grain:
M_psi[-1-i_y, i_x] = 1
elif distance >= r_grain:
M_psi[-1-i_y, i_x] = 0
# compute surface grains and water
Surface_grain = np.sum(M_psi)/M_psi.size*dict_user['dim_domain']*dict_user['dim_domain']
Surface_water = dict_user['dim_domain']*dict_user['dim_domain'] - Surface_grain
# compute ratio
m_H20_m_cement = (Surface_water*dict_user['rho_water'])/(Surface_grain*dict_user['rho_g'])
# print result
print()
print('m_H20/m_cement:', round(m_H20_m_cement,2),'targetted')
# Compute phi
# center and radius definition
i_x_seed = len(L_x)-1
i_y_seed = int(len(L_y)/2)
center_seed = np.array([L_x[i_x_seed], L_y[i_y_seed]])
r_seed = 2*dict_user['w_int']
# compute map
n_nodes = int(r_seed/(L_x[1]-L_x[0]))+8
for i_x in range(max(0,i_x_seed-n_nodes),min(i_x_seed+n_nodes+1,len(L_x))):
for i_y in range(max(0,i_y_seed-n_nodes),min(i_y_seed+n_nodes+1,len(L_y))):
x = L_x[i_x]
y = L_y[i_y]
Point = np.array([x, y])
distance = np.linalg.norm(Point-center_seed)
# Update map psi
if M_phi[-1-i_y, i_x] == 0 : # do not erase data already written
if distance <= r_seed:
M_phi[-1-i_y, i_x] = 1
elif distance >= r_seed:
M_phi[-1-i_y, i_x] = 0
# print psi/phi map
M_phi_psi = M_psi + 2*M_phi
fig, (ax1) = plt.subplots(1,1,figsize=(16,9))
title_fontsize = 30
im = ax1.imshow(M_phi_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]), vmax=2)
cbar = fig.colorbar(im, ax=ax1)
cbar.set_ticks(ticks=[0, 1, 2], labels=['Pore', 'Source', 'C-S-H'])
fig.tight_layout()
fig.savefig('png/IC_one_map.png')
plt.close(fig)
# adapt maps
M_psi = M_psi - 0.5
M_phi = M_phi - 0.5
# compute the signed distance functions
sd_phi = skfmm.distance(M_phi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]]))
sd_psi = skfmm.distance(M_psi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]]))
# compute the phase field variables
for i_x in range(len(L_x)):
for i_y in range(len(L_y)):
# phi
if sd_phi[i_y, i_x] > dict_user['w_int']/2: # inside the grain
M_phi[i_y, i_x] = 1
elif sd_phi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain
M_phi[i_y, i_x] = 0
else : # in the interface
M_phi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_phi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int'])))
# psi
if sd_psi[i_y, i_x] > dict_user['w_int']/2: # inside the grain
M_psi[i_y, i_x] = 1
elif sd_psi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain
M_psi[i_y, i_x] = 0
else : # in the interface
M_psi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_psi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int'])))
# result
print()
print('Mean value of psi:', round(np.sum(M_psi)/M_psi.size,2))
print('Mean value of phi:', round(np.sum(M_phi)/M_phi.size,2))
# Plot maps
fig, ((ax1),(ax2),(ax3)) = plt.subplots(3,1,figsize=(9,25))
# parameters
title_fontsize = 30
# psi
im = ax1.imshow(M_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax1)
ax1.set_title(r'Map of $\psi$',fontsize = title_fontsize)
# phi
im = ax2.imshow(M_phi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax2)
ax2.set_title(r'Map of $\phi$',fontsize = title_fontsize)
# c
im = ax3.imshow(M_c, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax3)
ax3.set_title(r'Map of c',fontsize = title_fontsize)
fig.savefig('png/IC.png')
plt.close(fig)
# save in dicts
dict_sample['L_x'] = L_x
dict_sample['L_y'] = L_y
dict_sample['M_psi'] = M_psi
dict_sample['M_phi'] = M_phi
dict_sample['M_c'] = M_c
# Write data
file_to_write_psi = open('txt/psi.txt','w')
file_to_write_phi = open('txt/phi.txt','w')
file_to_write_c = open('txt/c.txt','w')
# x
file_to_write_psi.write('AXIS X\n')
file_to_write_phi.write('AXIS X\n')
file_to_write_c.write('AXIS X\n')
line = ''
for x in dict_sample['L_x']:
line = line + str(x)+ ' '
line = line + '\n'
file_to_write_psi.write(line)
file_to_write_phi.write(line)
file_to_write_c.write(line)
# y
file_to_write_psi.write('AXIS Y\n')
file_to_write_phi.write('AXIS Y\n')
file_to_write_c.write('AXIS Y\n')
line = ''
for y in dict_sample['L_y']:
line = line + str(y)+ ' '
line = line + '\n'
file_to_write_psi.write(line)
file_to_write_phi.write(line)
file_to_write_c.write(line)
# data
file_to_write_psi.write('DATA\n')
file_to_write_phi.write('DATA\n')
file_to_write_c.write('DATA\n')
for l in range(len(dict_sample['L_y'])):
for c in range(len(dict_sample['L_x'])):
file_to_write_psi.write(str(M_psi[-1-l][c])+'\n')
file_to_write_phi.write(str(M_phi[-1-l][c])+'\n')
file_to_write_c.write(str(M_c[-1-l][c])+'\n')
# close
file_to_write_psi.close()
file_to_write_phi.close()
file_to_write_c.close()
#-------------------------------------------------------------------------------
def Insert_Grains_Seed(dict_sample, dict_user):
'''
Insert n_grains grains in the domain. The grains are circle defined by a radius (uniform distribution).
The position of the grains is randomly set, avoiding overlap between particules.
A maximum number of tries is done per grain insertion.
Map of phi, psi and c are generated.
'''
# Initialize the arrays
M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh']))
M_phi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh']))
M_c = dict_user['C_eq_phi']*np.ones((dict_user['n_mesh'],dict_user['n_mesh']))
# Initialize the mesh lists
L_x = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh'])
L_y = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh'])
# Insert grains
L_pos_grains = []
L_radius_grains = []
m_H20_m_cement = 2*dict_user['w_g_target']
# check conditions
while m_H20_m_cement > dict_user['w_g_target'] :
# Random radius of the grain
if dict_user['PSD_mode'] == 'Uniform':
R_try = max(dict_user['R']*(1+dict_user['R_var']*(random.random()-0.5)*2), dict_user['d_mesh']*5)
if dict_user['PSD_mode'] == 'Given':
i_bin = np.random.choice(len(dict_user['L_perc_R']), p=dict_user['L_perc_R'])
R_try = random.uniform(dict_user['L_R'][i_bin], dict_user['L_R'][i_bin+1])
# Random position of the grain center
x_try = (dict_user['dim_domain']/2+R_try)*(random.random()-0.5)*2
y_try = (dict_user['dim_domain']/2+R_try)*(random.random()-0.5)*2
# Save grain
L_pos_grains.append(np.array([x_try, y_try]))
L_radius_grains.append(R_try)
# compute surface grains and water
Surface_grain = 0
for i_grain in range(len(L_pos_grains)):
Surface_grain = Surface_grain + math.pi*L_radius_grains[i_grain]**2
Surface_water = dict_user['dim_domain']*dict_user['dim_domain'] - Surface_grain
# compute ratio
m_H20_m_cement = (Surface_water*dict_user['rho_water'])/(Surface_grain*dict_user['rho_g'])
# output
print('Compute IC:',round(m_H20_m_cement,2),'/',dict_user['w_g_target'],'targetted')
# compute the configuration
for i_steps in range(1, dict_user['n_steps']+1):
print('Increase radius step',i_steps,'/',dict_user['n_steps'])
# compute tempo radius at this step
L_radius_grains_step = []
for radius in L_radius_grains:
L_radius_grains_step.append(radius*i_steps/dict_user['n_steps'])
# compute virtual grain due to periodic condition
L_pos_grains_virtual, L_radius_grains_virtual, L_i_grain_virtual = compute_virtual(dict_user, L_pos_grains, L_radius_grains_step)
# check if there is no overlap
overlap, L_overlap, L_overlap_virtual = check_overlap(L_radius_grains_step, L_pos_grains,\
L_radius_grains_virtual, L_pos_grains_virtual, L_i_grain_virtual,\
dict_user['factor_int'])
while overlap:
# save old positions
L_pos_grains_old = L_pos_grains.copy()
L_pos_grains_virtual_old = L_pos_grains_virtual.copy()
# iterate on overlap list to move problematic grains
if L_overlap != []:
overlap = L_overlap[0]
# get indices
i_g = overlap[0]
j_g = overlap[1]
# get radius
r_i = L_radius_grains_step[i_g]
r_j = L_radius_grains_step[j_g]
# get displacement vector (i->j)
u_ij = np.array(L_pos_grains[j_g] - L_pos_grains[i_g])
u_ij = u_ij/np.linalg.norm(u_ij)
# move grain
L_pos_grains[i_g] = L_pos_grains_old[j_g] - u_ij*(r_i+r_j+dict_user['factor_int'])
L_pos_grains[j_g] = L_pos_grains_old[i_g] + u_ij*(r_i+r_j+dict_user['factor_int'])
else :
overlap = L_overlap_virtual[0]
# get indices
i_g = overlap[0]
j_g_virtual = overlap[1]
j_g = overlap[2]
# get radius
r_i = L_radius_grains_step[i_g]
r_j = L_radius_grains_step[j_g]
# get displacement vector (i->j)
u_ij = np.array(L_pos_grains_virtual[j_g_virtual] - L_pos_grains[i_g])
u_ij = u_ij/np.linalg.norm(u_ij)
# move grain
L_pos_grains[i_g] = L_pos_grains_virtual_old[j_g_virtual] - u_ij*(r_i+r_j+2*dict_user['factor_int'])
# check position of grain after displacement
for i_grain in range(len(L_pos_grains)):
# - x limit
if L_pos_grains[i_grain][0] < -dict_user['dim_domain']/2 - L_radius_grains_step[i_grain]:
L_pos_grains[i_grain] = L_pos_grains[i_grain] + np.array([ dict_user['dim_domain'], 0])
# + x limit
if dict_user['dim_domain']/2 + L_radius_grains_step[i_grain] < L_pos_grains[i_grain][0]:
L_pos_grains[i_grain] = L_pos_grains[i_grain] + np.array([-dict_user['dim_domain'], 0])
# - y limit
if L_pos_grains[i_grain][1] < -dict_user['dim_domain']/2 - L_radius_grains_step[i_grain]:
L_pos_grains[i_grain] = L_pos_grains[i_grain] + np.array([0, dict_user['dim_domain']])
# + y limit
if dict_user['dim_domain']/2 + L_radius_grains_step[i_grain] < L_pos_grains[i_grain][1]:
L_pos_grains[i_grain] = L_pos_grains[i_grain] + np.array([0, -dict_user['dim_domain']])
# compute virtual grain due to periodic condition
L_pos_grains_virtual, L_radius_grains_virtual, L_i_grain_virtual = compute_virtual(dict_user, L_pos_grains, L_radius_grains_step)
# look if overlap exists
overlap, L_overlap, L_overlap_virtual = check_overlap(L_radius_grains_step, L_pos_grains,\
L_radius_grains_virtual, L_pos_grains_virtual, L_i_grain_virtual,\
dict_user['factor_int'])
# combine the final list
L_pos_grains_real_virtual = L_pos_grains + L_pos_grains_virtual
L_radius_grains_real_virtual = L_radius_grains + L_radius_grains_virtual
# compute m_H20_m_cement
M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh']))
# iterate on grains
for i_grain in range(len(L_pos_grains_real_virtual)):
x_grain = L_pos_grains_real_virtual[i_grain][0]
y_grain = L_pos_grains_real_virtual[i_grain][1]
Center_grain = np.array([x_grain, y_grain])
r_grain = L_radius_grains_real_virtual[i_grain]
# find the nearest node of the center
L_search = list(abs(np.array(L_x-x_grain)))
i_x_center = L_search.index(min(L_search))
L_search = list(abs(np.array(L_y-y_grain)))
i_y_center = L_search.index(min(L_search))
# compute the number of node (depending on the radius)
n_nodes = int(r_grain/(L_x[1]-L_x[0]))+4
for i_x in range(max(0,i_x_center-n_nodes),min(i_x_center+n_nodes+1,len(L_x))):
for i_y in range(max(0,i_y_center-n_nodes),min(i_y_center+n_nodes+1,len(L_y))):
x = L_x[i_x]
y = L_y[i_y]
Point = np.array([x, y])
distance = np.linalg.norm(Point-Center_grain)
# Update map psi
if M_psi[-1-i_y, i_x] == 0 : # do not erase data already written
if distance <= r_grain:
M_psi[-1-i_y, i_x] = 1
elif distance >= r_grain:
M_psi[-1-i_y, i_x] = 0
# compute surface grains and water
Surface_grain = np.sum(M_psi)/M_psi.size*dict_user['dim_domain']*dict_user['dim_domain']
Surface_water = dict_user['dim_domain']*dict_user['dim_domain'] - Surface_grain
# compute ratio
m_H20_m_cement = (Surface_water*dict_user['rho_water'])/(Surface_grain*dict_user['rho_g'])
# print result
print()
print(len(L_radius_grains),'grains inserted')
print('psd:', round(np.mean(L_radius_grains),1),'(mean)', round(np.min(L_radius_grains),1),'(min)', round(np.max(L_radius_grains),1),'(max)')
print('m_H20/m_cement:', round(m_H20_m_cement,2),'/',dict_user['w_g_target'],'targetted')
# Compute phi
n_seed = dict_user['n_seed']
for i_seed in range(n_seed):
i_try = 0
seed_created = False
while not seed_created and i_try < 500:
i_try = i_try + 1
# generate a seed
i_x_seed = random.randint(0, len(L_x)-1)
i_y_seed = random.randint(0, len(L_y)-1)
center_seed = np.array([L_x[i_x_seed], L_y[i_y_seed]])
r_seed = dict_user['w_int']+dict_user['d_mesh']
# verify the node is not in a cement source
# and not far from a source
if M_psi[-1-i_y_seed, i_x_seed] != 1:
close_seed = False
for i_grain in range(len(L_pos_grains_real_virtual)):
d_seed_grain = np.linalg.norm(center_seed-L_pos_grains_real_virtual[i_grain])
if d_seed_grain < L_radius_grains_real_virtual[i_grain]+2*r_seed:
close_seed = True
if close_seed:
seed_created = True
# compute the number of node (depending on the radius)
n_nodes = 2*int(r_seed/(L_x[1]-L_x[0]))
for i_x in range(max(0,i_x_seed-n_nodes),min(i_x_seed+n_nodes+1,len(L_x))):
for i_y in range(max(0,i_y_seed-n_nodes),min(i_y_seed+n_nodes+1,len(L_y))):
x = L_x[i_x]
y = L_y[i_y]
Point = np.array([x, y])
distance = np.linalg.norm(Point-center_seed)
# Update map psi
if M_phi[-1-i_y, i_x] == 0 : # do not erase data already written
if distance <= r_seed:
M_phi[-1-i_y, i_x] = 1
elif distance >= r_seed:
M_phi[-1-i_y, i_x] = 0
# print psi/phi map
M_phi_psi = M_psi + 2*M_phi
fig, (ax1) = plt.subplots(1,1,figsize=(16,9))
title_fontsize = 30
im = ax1.imshow(M_phi_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]), vmax=2)
cbar = fig.colorbar(im, ax=ax1)
cbar.set_ticks(ticks=[0, 1, 2], labels=['Pore', 'Source', 'C-S-H'])
fig.tight_layout()
fig.savefig('png/IC_one_map.png')
plt.close(fig)
# adapt maps
M_psi = M_psi - 0.5
if n_seed > 0:
M_phi = M_phi - 0.5
# compute the signed distance functions
sd_psi = skfmm.distance(M_psi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]]))
if n_seed > 0:
sd_phi = skfmm.distance(M_phi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]]))
# compute the phase field variables
for i_x in range(len(L_x)):
for i_y in range(len(L_y)):
# phi
if n_seed > 0:
if sd_phi[i_y, i_x] > dict_user['w_int']/2: # inside the grain
M_phi[i_y, i_x] = 1
elif sd_phi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain
M_phi[i_y, i_x] = 0
else : # in the interface
M_phi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_phi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int'])))
# psi
if sd_psi[i_y, i_x] > dict_user['w_int']/2: # inside the grain
M_psi[i_y, i_x] = 1
elif sd_psi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain
M_psi[i_y, i_x] = 0
else : # in the interface
M_psi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_psi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int'])))
# result
print()
print('Mean value of psi:', round(np.sum(M_psi)/M_psi.size,2))
print('Mean value of phi:', round(np.sum(M_phi)/M_phi.size,2))
# Plot maps
fig, ((ax1),(ax2),(ax3)) = plt.subplots(3,1,figsize=(9,25))
# parameters
title_fontsize = 30
# psi
im = ax1.imshow(M_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax1)
ax1.set_title(r'Map of $\psi$',fontsize = title_fontsize)
# phi
im = ax2.imshow(M_phi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax2)
ax2.set_title(r'Map of $\phi$',fontsize = title_fontsize)
# c
im = ax3.imshow(M_c, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax3)
ax3.set_title(r'Map of c',fontsize = title_fontsize)
fig.savefig('png/IC.png')
plt.close(fig)
# save in dicts
dict_sample['L_x'] = L_x
dict_sample['L_y'] = L_y
dict_sample['M_psi'] = M_psi
dict_sample['M_phi'] = M_phi
dict_sample['M_c'] = M_c
# Write data
file_to_write_psi = open('txt/psi.txt','w')
file_to_write_phi = open('txt/phi.txt','w')
file_to_write_c = open('txt/c.txt','w')
# x
file_to_write_psi.write('AXIS X\n')
file_to_write_phi.write('AXIS X\n')
file_to_write_c.write('AXIS X\n')
line = ''
for x in dict_sample['L_x']:
line = line + str(x)+ ' '
line = line + '\n'
file_to_write_psi.write(line)
file_to_write_phi.write(line)
file_to_write_c.write(line)
# y
file_to_write_psi.write('AXIS Y\n')
file_to_write_phi.write('AXIS Y\n')
file_to_write_c.write('AXIS Y\n')
line = ''
for y in dict_sample['L_y']:
line = line + str(y)+ ' '
line = line + '\n'
file_to_write_psi.write(line)
file_to_write_phi.write(line)
file_to_write_c.write(line)
# data
file_to_write_psi.write('DATA\n')
file_to_write_phi.write('DATA\n')
file_to_write_c.write('DATA\n')
for l in range(len(dict_sample['L_y'])):
for c in range(len(dict_sample['L_x'])):
file_to_write_psi.write(str(M_psi[-1-l][c])+'\n')
file_to_write_phi.write(str(M_phi[-1-l][c])+'\n')
file_to_write_c.write(str(M_c[-1-l][c])+'\n')
# close
file_to_write_psi.close()
file_to_write_phi.close()
file_to_write_c.close()
#-------------------------------------------------------------------------------
def Insert_Powder_Seed(dict_sample, dict_user):
'''
Insert n_grains grains in the domain. The grains are circle defined by a radius (uniform distribution).
The position of the grains is randomly set, overlap between particules is allowed.
A ratio of water mass / cement mass is targetted.
Map of phi, psi and c are generated.
'''
# Initialize the arrays
M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh']))
M_phi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh']))
M_c = dict_user['C_eq_phi']*np.ones((dict_user['n_mesh'],dict_user['n_mesh']))
# Initialize the mesh lists
L_x = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh'])
L_y = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh'])
# Insert grains
m_H20_m_cement = 2*dict_user['w_g_target']
while m_H20_m_cement > dict_user['w_g_target']:
# Random radius of the grain
r_grain = max(dict_user['R']*(1+dict_user['R_var']*(random.random()-0.5)*2), dict_user['d_mesh']*5)
# Random position of the grain center
x_grain = (dict_user['dim_domain']/2+r_grain)*(random.random()-0.5)*2
y_grain = (dict_user['dim_domain']/2+r_grain)*(random.random()-0.5)*2
Center_grain = np.array([x_grain, y_grain])
# find the nearest node of the center
L_search = list(abs(np.array(L_x-x_grain)))
i_x_center = L_search.index(min(L_search))
L_search = list(abs(np.array(L_y-y_grain)))
i_y_center = L_search.index(min(L_search))
# compute the number of node (depending on the radius)
n_nodes = int(r_grain/(L_x[1]-L_x[0]))+15
for i_x in range(max(0,i_x_center-n_nodes),min(i_x_center+n_nodes+1,len(L_x))):
for i_y in range(max(0,i_y_center-n_nodes),min(i_y_center+n_nodes+1,len(L_y))):
x = L_x[i_x]
y = L_y[i_y]
Point = np.array([x, y])
distance = np.linalg.norm(Point-Center_grain)
# Update map psi
if distance <= r_grain :
M_psi[-1-i_y, i_x] = 1
# compute the ratio water mass/cement mass
Surface_grain = np.sum(M_psi)*(L_x[1]-L_x[0])*(L_y[1]-L_y[0])
Surface_water = dict_user['dim_domain']*dict_user['dim_domain'] - Surface_grain
m_H20_m_cement = Surface_water*dict_user['rho_water']/(Surface_grain*dict_user['rho_g'])
# output
print('Compute IC:',round(m_H20_m_cement,2),'/',dict_user['w_g_target'],'targetted')
# Compute phi
n_seed = dict_user['n_seed']
for i_seed in range(n_seed):
i_try = 0
seed_created = False
while not seed_created and i_try < 100:
i_try = i_try + 1
# generate a seed
i_x_seed = random.randint(0, len(L_x)-1)
i_y_seed = random.randint(0, len(L_y)-1)
center_seed = np.array([L_x[i_x_seed], L_y[i_y_seed]])
# verify the node is not in a cement source
if M_psi[-1-i_y_seed, i_x_seed] != 1:
seed_created = True
# generate the seed
r_seed = 1.3*dict_user['w_int']
# compute the number of node (depending on the radius)
n_nodes = int(r_seed/(L_x[1]-L_x[0]))+4
for i_x in range(max(0,i_x_seed-n_nodes),min(i_x_seed+n_nodes+1,len(L_x))):
for i_y in range(max(0,i_y_seed-n_nodes),min(i_y_seed+n_nodes+1,len(L_y))):
x = L_x[i_x]
y = L_y[i_y]
Point = np.array([x, y])
distance = np.linalg.norm(Point-center_seed)
# Update map psi
if M_phi[-1-i_y, i_x] == 0 : # do not erase data already written
if distance <= r_seed:
M_phi[-1-i_y, i_x] = 1
elif distance >= r_seed:
M_phi[-1-i_y, i_x] = 0
# print psi/phi map
M_phi_psi = M_psi + 2*M_phi
fig, (ax1) = plt.subplots(1,1,figsize=(16,9))
title_fontsize = 30
im = ax1.imshow(M_phi_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]), vmax=2)
cbar = fig.colorbar(im, ax=ax1)
cbar.set_ticks(ticks=[0, 1, 2], labels=['Pore', 'Source', 'C-S-H'])
fig.tight_layout()
fig.savefig('png/IC_one_map.png')
plt.close(fig)
# adapt maps
M_psi = M_psi - 0.5
M_phi = M_phi - 0.5
# compute the signed distance functions
sd_phi = skfmm.distance(M_phi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]]))
sd_psi = skfmm.distance(M_psi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]]))
# compute the phase field variables
for i_x in range(len(L_x)):
for i_y in range(len(L_y)):
# phi
if sd_phi[i_y, i_x] > dict_user['w_int']/2: # inside the grain
M_phi[i_y, i_x] = 1
elif sd_phi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain
M_phi[i_y, i_x] = 0
else : # in the interface
M_phi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_phi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int'])))
# psi
if sd_psi[i_y, i_x] > dict_user['w_int']/2: # inside the grain
M_psi[i_y, i_x] = 1
elif sd_psi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain
M_psi[i_y, i_x] = 0
else : # in the interface
M_psi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_psi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int'])))
# result
print()
print('Mean value of psi:', round(np.sum(M_psi)/M_psi.size,2))
print('Mean value of phi:', round(np.sum(M_phi)/M_phi.size,2))
# Plot maps
fig, ((ax1),(ax2),(ax3)) = plt.subplots(3,1,figsize=(9,25))
# parameters
title_fontsize = 30
# psi
im = ax1.imshow(M_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax1)
ax1.set_title(r'Map of $\psi$',fontsize = title_fontsize)
# phi
im = ax2.imshow(M_phi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax2)
ax2.set_title(r'Map of $\phi$',fontsize = title_fontsize)
# c
im = ax3.imshow(M_c, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]))
fig.colorbar(im, ax=ax3)
ax3.set_title(r'Map of c',fontsize = title_fontsize)
fig.savefig('png/IC.png')
plt.close(fig)
# save in dicts
dict_sample['L_x'] = L_x
dict_sample['L_y'] = L_y
dict_sample['M_psi'] = M_psi
dict_sample['M_phi'] = M_phi
dict_sample['M_c'] = M_c
# Write data
file_to_write_psi = open('txt/psi.txt','w')
file_to_write_phi = open('txt/phi.txt','w')
file_to_write_c = open('txt/c.txt','w')
# x
file_to_write_psi.write('AXIS X\n')
file_to_write_phi.write('AXIS X\n')
file_to_write_c.write('AXIS X\n')
line = ''
for x in dict_sample['L_x']:
line = line + str(x)+ ' '
line = line + '\n'
file_to_write_psi.write(line)
file_to_write_phi.write(line)
file_to_write_c.write(line)
# y
file_to_write_psi.write('AXIS Y\n')
file_to_write_phi.write('AXIS Y\n')
file_to_write_c.write('AXIS Y\n')
line = ''
for y in dict_sample['L_y']:
line = line + str(y)+ ' '
line = line + '\n'
file_to_write_psi.write(line)
file_to_write_phi.write(line)
file_to_write_c.write(line)
# data
file_to_write_psi.write('DATA\n')
file_to_write_phi.write('DATA\n')
file_to_write_c.write('DATA\n')
for l in range(len(dict_sample['L_y'])):
for c in range(len(dict_sample['L_x'])):
file_to_write_psi.write(str(M_psi[-1-l][c])+'\n')
file_to_write_phi.write(str(M_phi[-1-l][c])+'\n')
file_to_write_c.write(str(M_c[-1-l][c])+'\n')
# close
file_to_write_psi.close()
file_to_write_phi.close()
file_to_write_c.close()
Functions
def check_overlap()
-
Determine if grains are overlapping.
Used in Insert_Grains() function.
Expand source code
def check_overlap(L_radius_grains, L_pos_grains, L_radius_grains_virtual, L_pos_grains_virtual, L_i_grain_virtual, factor_int): ''' Determine if grains are overlapping. Used in Insert_Grains() function. ''' overlap = False # real - real L_overlap = [] for i_g in range(len(L_radius_grains)-1): # radius of grains radius_i = L_radius_grains[i_g] # position of grains pos_i = L_pos_grains[i_g] for j_g in range(i_g+1, len(L_radius_grains)): # radius of grains radius_j = L_radius_grains[j_g] # position of grains pos_j = L_pos_grains[j_g] # check distance if np.linalg.norm(pos_i-pos_j) < radius_i+radius_j+factor_int: overlap = True L_overlap.append((i_g, j_g)) # real - virtual L_overlap_virtual = [] for i_g in range(len(L_radius_grains)): # radius of grains radius_i = L_radius_grains[i_g] # position of grains pos_i = L_pos_grains[i_g] for j_g in range(len(L_radius_grains_virtual)): # radius of grains radius_j = L_radius_grains_virtual[j_g] # position of grains pos_j = L_pos_grains_virtual[j_g] # check distance if np.linalg.norm(pos_i-pos_j) < radius_i+radius_j+factor_int: overlap = True L_overlap_virtual.append((i_g, j_g, L_i_grain_virtual[j_g])) return overlap, L_overlap, L_overlap_virtual
def compute_virtual()
-
Compute virtual grains with the periodic conditions.
Expand source code
def compute_virtual(dict_user, L_pos_grains, L_radius_grains_step): ''' Compute virtual grains with the periodic conditions. ''' L_pos_grains_virtual = [] L_radius_grains_virtual = [] L_i_grain_virtual = [] for i_grain in range(len(L_pos_grains)): per_x_p = False per_x_m = False per_y_p = False per_y_m = False # - x limit if L_pos_grains[i_grain][0] < -dict_user['dim_domain']/2 + L_radius_grains_step[i_grain]: L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([ dict_user['dim_domain'], 0])) L_radius_grains_virtual.append(L_radius_grains_step[i_grain]) L_i_grain_virtual.append(i_grain) per_x_m = True # + x limit if dict_user['dim_domain']/2 - L_radius_grains_step[i_grain] < L_pos_grains[i_grain][0]: L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([-dict_user['dim_domain'], 0])) L_radius_grains_virtual.append(L_radius_grains_step[i_grain]) L_i_grain_virtual.append(i_grain) per_x_p = True # - y limit if L_pos_grains[i_grain][1] < -dict_user['dim_domain']/2 + L_radius_grains_step[i_grain]: L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([0, dict_user['dim_domain']])) L_radius_grains_virtual.append(L_radius_grains_step[i_grain]) L_i_grain_virtual.append(i_grain) per_y_m = True # + y limit if dict_user['dim_domain']/2 - L_radius_grains_step[i_grain] < L_pos_grains[i_grain][1]: L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([0, -dict_user['dim_domain']])) L_radius_grains_virtual.append(L_radius_grains_step[i_grain]) L_i_grain_virtual.append(i_grain) per_y_p = True # - x and - y limits if per_x_m and per_y_m: L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([ dict_user['dim_domain'], dict_user['dim_domain']])) L_radius_grains_virtual.append(L_radius_grains_step[i_grain]) L_i_grain_virtual.append(i_grain) # - x and + y limits if per_x_m and per_y_p: L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([ dict_user['dim_domain'], -dict_user['dim_domain']])) L_radius_grains_virtual.append(L_radius_grains_step[i_grain]) L_i_grain_virtual.append(i_grain) # + x and - y limit if per_x_p and per_y_m: L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([ -dict_user['dim_domain'], dict_user['dim_domain']])) L_radius_grains_virtual.append(L_radius_grains_step[i_grain]) L_i_grain_virtual.append(i_grain) # + x and + y limit if per_x_p and per_y_p: L_pos_grains_virtual.append(L_pos_grains[i_grain] + np.array([ -dict_user['dim_domain'], -dict_user['dim_domain']])) L_radius_grains_virtual.append(L_radius_grains_step[i_grain]) L_i_grain_virtual.append(i_grain) return L_pos_grains_virtual, L_radius_grains_virtual, L_i_grain_virtual
def Insert_One_Grain_Seed()
-
Insert one grain in the domain. The grain is circle defined by a radius.
Map of phi, psi and c are generated.
Expand source code
def Insert_One_Grain_Seed(dict_sample, dict_user): ''' Insert one grain in the domain. The grain is circle defined by a radius. Map of phi, psi and c are generated. ''' # Initialize the arrays M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh'])) M_phi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh'])) M_c = dict_user['C_eq_phi']*np.ones((dict_user['n_mesh'],dict_user['n_mesh'])) # Initialize the mesh lists L_x = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh']) L_y = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh']) # compute m_H20_m_cement M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh'])) # iterate on grains x_grain = 0 y_grain = 0 Center_grain = np.array([x_grain, y_grain]) r_grain = dict_user['R'] # find the nearest node of the center L_search = list(abs(np.array(L_x-x_grain))) i_x_center = L_search.index(min(L_search)) L_search = list(abs(np.array(L_y-y_grain))) i_y_center = L_search.index(min(L_search)) # compute the number of node (depending on the radius) n_nodes = int(r_grain/(L_x[1]-L_x[0]))+4 for i_x in range(max(0,i_x_center-n_nodes),min(i_x_center+n_nodes+1,len(L_x))): for i_y in range(max(0,i_y_center-n_nodes),min(i_y_center+n_nodes+1,len(L_y))): x = L_x[i_x] y = L_y[i_y] Point = np.array([x, y]) distance = np.linalg.norm(Point-Center_grain) # Update map psi if M_psi[-1-i_y, i_x] == 0 : # do not erase data already written if distance <= r_grain: M_psi[-1-i_y, i_x] = 1 elif distance >= r_grain: M_psi[-1-i_y, i_x] = 0 # compute surface grains and water Surface_grain = np.sum(M_psi)/M_psi.size*dict_user['dim_domain']*dict_user['dim_domain'] Surface_water = dict_user['dim_domain']*dict_user['dim_domain'] - Surface_grain # compute ratio m_H20_m_cement = (Surface_water*dict_user['rho_water'])/(Surface_grain*dict_user['rho_g']) # print result print() print('m_H20/m_cement:', round(m_H20_m_cement,2),'targetted') # Compute phi n_seed = dict_user['n_seed'] for i_seed in range(n_seed): i_try = 0 seed_created = False while not seed_created and i_try < 100: i_try = i_try + 1 # generate a seed i_x_seed = random.randint(0, len(L_x)-1) i_y_seed = random.randint(0, len(L_y)-1) center_seed = np.array([L_x[i_x_seed], L_y[i_y_seed]]) # verify the node is not in a cement source if M_psi[-1-i_y_seed, i_x_seed] != 1: seed_created = True # generate the seed r_seed = 1.5*dict_user['w_int'] # compute the number of node (depending on the radius) n_nodes = int(r_seed/(L_x[1]-L_x[0]))+4 for i_x in range(max(0,i_x_seed-n_nodes),min(i_x_seed+n_nodes+1,len(L_x))): for i_y in range(max(0,i_y_seed-n_nodes),min(i_y_seed+n_nodes+1,len(L_y))): x = L_x[i_x] y = L_y[i_y] Point = np.array([x, y]) distance = np.linalg.norm(Point-center_seed) # Update map psi if M_phi[-1-i_y, i_x] == 0 : # do not erase data already written if distance <= r_seed: M_phi[-1-i_y, i_x] = 1 elif distance >= r_seed: M_phi[-1-i_y, i_x] = 0 # print psi/phi map M_phi_psi = M_psi + 2*M_phi fig, (ax1) = plt.subplots(1,1,figsize=(16,9)) title_fontsize = 30 im = ax1.imshow(M_phi_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]), vmax=2) cbar = fig.colorbar(im, ax=ax1) cbar.set_ticks(ticks=[0, 1, 2], labels=['Pore', 'Source', 'C-S-H']) fig.tight_layout() fig.savefig('png/IC_one_map.png') plt.close(fig) # adapt maps M_psi = M_psi - 0.5 M_phi = M_phi - 0.5 # compute the signed distance functions sd_phi = skfmm.distance(M_phi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]])) sd_psi = skfmm.distance(M_psi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]])) # compute the phase field variables for i_x in range(len(L_x)): for i_y in range(len(L_y)): # phi if sd_phi[i_y, i_x] > dict_user['w_int']/2: # inside the grain M_phi[i_y, i_x] = 1 elif sd_phi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain M_phi[i_y, i_x] = 0 else : # in the interface M_phi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_phi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int']))) # psi if sd_psi[i_y, i_x] > dict_user['w_int']/2: # inside the grain M_psi[i_y, i_x] = 1 elif sd_psi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain M_psi[i_y, i_x] = 0 else : # in the interface M_psi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_psi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int']))) # result print() print('Mean value of psi:', round(np.sum(M_psi)/M_psi.size,2)) print('Mean value of phi:', round(np.sum(M_phi)/M_phi.size,2)) # Plot maps fig, ((ax1),(ax2),(ax3)) = plt.subplots(3,1,figsize=(9,25)) # parameters title_fontsize = 30 # psi im = ax1.imshow(M_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax1) ax1.set_title(r'Map of $\psi$',fontsize = title_fontsize) # phi im = ax2.imshow(M_phi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax2) ax2.set_title(r'Map of $\phi$',fontsize = title_fontsize) # c im = ax3.imshow(M_c, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax3) ax3.set_title(r'Map of c',fontsize = title_fontsize) fig.savefig('png/IC.png') plt.close(fig) # save in dicts dict_sample['L_x'] = L_x dict_sample['L_y'] = L_y dict_sample['M_psi'] = M_psi dict_sample['M_phi'] = M_phi dict_sample['M_c'] = M_c # Write data file_to_write_psi = open('txt/psi.txt','w') file_to_write_phi = open('txt/phi.txt','w') file_to_write_c = open('txt/c.txt','w') # x file_to_write_psi.write('AXIS X\n') file_to_write_phi.write('AXIS X\n') file_to_write_c.write('AXIS X\n') line = '' for x in dict_sample['L_x']: line = line + str(x)+ ' ' line = line + '\n' file_to_write_psi.write(line) file_to_write_phi.write(line) file_to_write_c.write(line) # y file_to_write_psi.write('AXIS Y\n') file_to_write_phi.write('AXIS Y\n') file_to_write_c.write('AXIS Y\n') line = '' for y in dict_sample['L_y']: line = line + str(y)+ ' ' line = line + '\n' file_to_write_psi.write(line) file_to_write_phi.write(line) file_to_write_c.write(line) # data file_to_write_psi.write('DATA\n') file_to_write_phi.write('DATA\n') file_to_write_c.write('DATA\n') for l in range(len(dict_sample['L_y'])): for c in range(len(dict_sample['L_x'])): file_to_write_psi.write(str(M_psi[-1-l][c])+'\n') file_to_write_phi.write(str(M_phi[-1-l][c])+'\n') file_to_write_c.write(str(M_c[-1-l][c])+'\n') # close file_to_write_psi.close() file_to_write_phi.close() file_to_write_c.close()
def Insert_One_Grain_Seed_Fixed()
-
Insert one grain in the domain. The grain is circle defined by a radius.
Map of phi, psi and c are generated.
Expand source code
def Insert_One_Grain_Seed_Fixed(dict_sample, dict_user): ''' Insert one grain in the domain. The grain is circle defined by a radius. Map of phi, psi and c are generated. ''' # Initialize the arrays M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh'])) M_phi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh'])) M_c = dict_user['C_eq_phi']*np.ones((dict_user['n_mesh'],dict_user['n_mesh'])) # Initialize the mesh lists L_x = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh']) L_y = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh']) # compute m_H20_m_cement M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh'])) # iterate on grains x_grain = 0 y_grain = 0 Center_grain = np.array([x_grain, y_grain]) r_grain = dict_user['R'] # find the nearest node of the center L_search = list(abs(np.array(L_x-x_grain))) i_x_center = L_search.index(min(L_search)) L_search = list(abs(np.array(L_y-y_grain))) i_y_center = L_search.index(min(L_search)) # compute the number of node (depending on the radius) n_nodes = int(r_grain/(L_x[1]-L_x[0]))+4 for i_x in range(max(0,i_x_center-n_nodes),min(i_x_center+n_nodes+1,len(L_x))): for i_y in range(max(0,i_y_center-n_nodes),min(i_y_center+n_nodes+1,len(L_y))): x = L_x[i_x] y = L_y[i_y] Point = np.array([x, y]) distance = np.linalg.norm(Point-Center_grain) # Update map psi if M_psi[-1-i_y, i_x] == 0 : # do not erase data already written if distance <= r_grain: M_psi[-1-i_y, i_x] = 1 elif distance >= r_grain: M_psi[-1-i_y, i_x] = 0 # compute surface grains and water Surface_grain = np.sum(M_psi)/M_psi.size*dict_user['dim_domain']*dict_user['dim_domain'] Surface_water = dict_user['dim_domain']*dict_user['dim_domain'] - Surface_grain # compute ratio m_H20_m_cement = (Surface_water*dict_user['rho_water'])/(Surface_grain*dict_user['rho_g']) # print result print() print('m_H20/m_cement:', round(m_H20_m_cement,2),'targetted') # Compute phi # center and radius definition i_x_seed = len(L_x)-1 i_y_seed = int(len(L_y)/2) center_seed = np.array([L_x[i_x_seed], L_y[i_y_seed]]) r_seed = 2*dict_user['w_int'] # compute map n_nodes = int(r_seed/(L_x[1]-L_x[0]))+8 for i_x in range(max(0,i_x_seed-n_nodes),min(i_x_seed+n_nodes+1,len(L_x))): for i_y in range(max(0,i_y_seed-n_nodes),min(i_y_seed+n_nodes+1,len(L_y))): x = L_x[i_x] y = L_y[i_y] Point = np.array([x, y]) distance = np.linalg.norm(Point-center_seed) # Update map psi if M_phi[-1-i_y, i_x] == 0 : # do not erase data already written if distance <= r_seed: M_phi[-1-i_y, i_x] = 1 elif distance >= r_seed: M_phi[-1-i_y, i_x] = 0 # print psi/phi map M_phi_psi = M_psi + 2*M_phi fig, (ax1) = plt.subplots(1,1,figsize=(16,9)) title_fontsize = 30 im = ax1.imshow(M_phi_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]), vmax=2) cbar = fig.colorbar(im, ax=ax1) cbar.set_ticks(ticks=[0, 1, 2], labels=['Pore', 'Source', 'C-S-H']) fig.tight_layout() fig.savefig('png/IC_one_map.png') plt.close(fig) # adapt maps M_psi = M_psi - 0.5 M_phi = M_phi - 0.5 # compute the signed distance functions sd_phi = skfmm.distance(M_phi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]])) sd_psi = skfmm.distance(M_psi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]])) # compute the phase field variables for i_x in range(len(L_x)): for i_y in range(len(L_y)): # phi if sd_phi[i_y, i_x] > dict_user['w_int']/2: # inside the grain M_phi[i_y, i_x] = 1 elif sd_phi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain M_phi[i_y, i_x] = 0 else : # in the interface M_phi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_phi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int']))) # psi if sd_psi[i_y, i_x] > dict_user['w_int']/2: # inside the grain M_psi[i_y, i_x] = 1 elif sd_psi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain M_psi[i_y, i_x] = 0 else : # in the interface M_psi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_psi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int']))) # result print() print('Mean value of psi:', round(np.sum(M_psi)/M_psi.size,2)) print('Mean value of phi:', round(np.sum(M_phi)/M_phi.size,2)) # Plot maps fig, ((ax1),(ax2),(ax3)) = plt.subplots(3,1,figsize=(9,25)) # parameters title_fontsize = 30 # psi im = ax1.imshow(M_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax1) ax1.set_title(r'Map of $\psi$',fontsize = title_fontsize) # phi im = ax2.imshow(M_phi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax2) ax2.set_title(r'Map of $\phi$',fontsize = title_fontsize) # c im = ax3.imshow(M_c, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax3) ax3.set_title(r'Map of c',fontsize = title_fontsize) fig.savefig('png/IC.png') plt.close(fig) # save in dicts dict_sample['L_x'] = L_x dict_sample['L_y'] = L_y dict_sample['M_psi'] = M_psi dict_sample['M_phi'] = M_phi dict_sample['M_c'] = M_c # Write data file_to_write_psi = open('txt/psi.txt','w') file_to_write_phi = open('txt/phi.txt','w') file_to_write_c = open('txt/c.txt','w') # x file_to_write_psi.write('AXIS X\n') file_to_write_phi.write('AXIS X\n') file_to_write_c.write('AXIS X\n') line = '' for x in dict_sample['L_x']: line = line + str(x)+ ' ' line = line + '\n' file_to_write_psi.write(line) file_to_write_phi.write(line) file_to_write_c.write(line) # y file_to_write_psi.write('AXIS Y\n') file_to_write_phi.write('AXIS Y\n') file_to_write_c.write('AXIS Y\n') line = '' for y in dict_sample['L_y']: line = line + str(y)+ ' ' line = line + '\n' file_to_write_psi.write(line) file_to_write_phi.write(line) file_to_write_c.write(line) # data file_to_write_psi.write('DATA\n') file_to_write_phi.write('DATA\n') file_to_write_c.write('DATA\n') for l in range(len(dict_sample['L_y'])): for c in range(len(dict_sample['L_x'])): file_to_write_psi.write(str(M_psi[-1-l][c])+'\n') file_to_write_phi.write(str(M_phi[-1-l][c])+'\n') file_to_write_c.write(str(M_c[-1-l][c])+'\n') # close file_to_write_psi.close() file_to_write_phi.close() file_to_write_c.close()
def Insert_Grains_Seed()
-
Insert n_grains grains in the domain. The grains are circle defined by a radius (uniform distribution). The position of the grains is randomly set, avoiding overlap between particules. A maximum number of tries is done per grain insertion.
Map of phi, psi and c are generated.
Expand source code
def Insert_Grains_Seed(dict_sample, dict_user): ''' Insert n_grains grains in the domain. The grains are circle defined by a radius (uniform distribution). The position of the grains is randomly set, avoiding overlap between particules. A maximum number of tries is done per grain insertion. Map of phi, psi and c are generated. ''' # Initialize the arrays M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh'])) M_phi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh'])) M_c = dict_user['C_eq_phi']*np.ones((dict_user['n_mesh'],dict_user['n_mesh'])) # Initialize the mesh lists L_x = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh']) L_y = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh']) # Insert grains L_pos_grains = [] L_radius_grains = [] m_H20_m_cement = 2*dict_user['w_g_target'] # check conditions while m_H20_m_cement > dict_user['w_g_target'] : # Random radius of the grain if dict_user['PSD_mode'] == 'Uniform': R_try = max(dict_user['R']*(1+dict_user['R_var']*(random.random()-0.5)*2), dict_user['d_mesh']*5) if dict_user['PSD_mode'] == 'Given': i_bin = np.random.choice(len(dict_user['L_perc_R']), p=dict_user['L_perc_R']) R_try = random.uniform(dict_user['L_R'][i_bin], dict_user['L_R'][i_bin+1]) # Random position of the grain center x_try = (dict_user['dim_domain']/2+R_try)*(random.random()-0.5)*2 y_try = (dict_user['dim_domain']/2+R_try)*(random.random()-0.5)*2 # Save grain L_pos_grains.append(np.array([x_try, y_try])) L_radius_grains.append(R_try) # compute surface grains and water Surface_grain = 0 for i_grain in range(len(L_pos_grains)): Surface_grain = Surface_grain + math.pi*L_radius_grains[i_grain]**2 Surface_water = dict_user['dim_domain']*dict_user['dim_domain'] - Surface_grain # compute ratio m_H20_m_cement = (Surface_water*dict_user['rho_water'])/(Surface_grain*dict_user['rho_g']) # output print('Compute IC:',round(m_H20_m_cement,2),'/',dict_user['w_g_target'],'targetted') # compute the configuration for i_steps in range(1, dict_user['n_steps']+1): print('Increase radius step',i_steps,'/',dict_user['n_steps']) # compute tempo radius at this step L_radius_grains_step = [] for radius in L_radius_grains: L_radius_grains_step.append(radius*i_steps/dict_user['n_steps']) # compute virtual grain due to periodic condition L_pos_grains_virtual, L_radius_grains_virtual, L_i_grain_virtual = compute_virtual(dict_user, L_pos_grains, L_radius_grains_step) # check if there is no overlap overlap, L_overlap, L_overlap_virtual = check_overlap(L_radius_grains_step, L_pos_grains,\ L_radius_grains_virtual, L_pos_grains_virtual, L_i_grain_virtual,\ dict_user['factor_int']) while overlap: # save old positions L_pos_grains_old = L_pos_grains.copy() L_pos_grains_virtual_old = L_pos_grains_virtual.copy() # iterate on overlap list to move problematic grains if L_overlap != []: overlap = L_overlap[0] # get indices i_g = overlap[0] j_g = overlap[1] # get radius r_i = L_radius_grains_step[i_g] r_j = L_radius_grains_step[j_g] # get displacement vector (i->j) u_ij = np.array(L_pos_grains[j_g] - L_pos_grains[i_g]) u_ij = u_ij/np.linalg.norm(u_ij) # move grain L_pos_grains[i_g] = L_pos_grains_old[j_g] - u_ij*(r_i+r_j+dict_user['factor_int']) L_pos_grains[j_g] = L_pos_grains_old[i_g] + u_ij*(r_i+r_j+dict_user['factor_int']) else : overlap = L_overlap_virtual[0] # get indices i_g = overlap[0] j_g_virtual = overlap[1] j_g = overlap[2] # get radius r_i = L_radius_grains_step[i_g] r_j = L_radius_grains_step[j_g] # get displacement vector (i->j) u_ij = np.array(L_pos_grains_virtual[j_g_virtual] - L_pos_grains[i_g]) u_ij = u_ij/np.linalg.norm(u_ij) # move grain L_pos_grains[i_g] = L_pos_grains_virtual_old[j_g_virtual] - u_ij*(r_i+r_j+2*dict_user['factor_int']) # check position of grain after displacement for i_grain in range(len(L_pos_grains)): # - x limit if L_pos_grains[i_grain][0] < -dict_user['dim_domain']/2 - L_radius_grains_step[i_grain]: L_pos_grains[i_grain] = L_pos_grains[i_grain] + np.array([ dict_user['dim_domain'], 0]) # + x limit if dict_user['dim_domain']/2 + L_radius_grains_step[i_grain] < L_pos_grains[i_grain][0]: L_pos_grains[i_grain] = L_pos_grains[i_grain] + np.array([-dict_user['dim_domain'], 0]) # - y limit if L_pos_grains[i_grain][1] < -dict_user['dim_domain']/2 - L_radius_grains_step[i_grain]: L_pos_grains[i_grain] = L_pos_grains[i_grain] + np.array([0, dict_user['dim_domain']]) # + y limit if dict_user['dim_domain']/2 + L_radius_grains_step[i_grain] < L_pos_grains[i_grain][1]: L_pos_grains[i_grain] = L_pos_grains[i_grain] + np.array([0, -dict_user['dim_domain']]) # compute virtual grain due to periodic condition L_pos_grains_virtual, L_radius_grains_virtual, L_i_grain_virtual = compute_virtual(dict_user, L_pos_grains, L_radius_grains_step) # look if overlap exists overlap, L_overlap, L_overlap_virtual = check_overlap(L_radius_grains_step, L_pos_grains,\ L_radius_grains_virtual, L_pos_grains_virtual, L_i_grain_virtual,\ dict_user['factor_int']) # combine the final list L_pos_grains_real_virtual = L_pos_grains + L_pos_grains_virtual L_radius_grains_real_virtual = L_radius_grains + L_radius_grains_virtual # compute m_H20_m_cement M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh'])) # iterate on grains for i_grain in range(len(L_pos_grains_real_virtual)): x_grain = L_pos_grains_real_virtual[i_grain][0] y_grain = L_pos_grains_real_virtual[i_grain][1] Center_grain = np.array([x_grain, y_grain]) r_grain = L_radius_grains_real_virtual[i_grain] # find the nearest node of the center L_search = list(abs(np.array(L_x-x_grain))) i_x_center = L_search.index(min(L_search)) L_search = list(abs(np.array(L_y-y_grain))) i_y_center = L_search.index(min(L_search)) # compute the number of node (depending on the radius) n_nodes = int(r_grain/(L_x[1]-L_x[0]))+4 for i_x in range(max(0,i_x_center-n_nodes),min(i_x_center+n_nodes+1,len(L_x))): for i_y in range(max(0,i_y_center-n_nodes),min(i_y_center+n_nodes+1,len(L_y))): x = L_x[i_x] y = L_y[i_y] Point = np.array([x, y]) distance = np.linalg.norm(Point-Center_grain) # Update map psi if M_psi[-1-i_y, i_x] == 0 : # do not erase data already written if distance <= r_grain: M_psi[-1-i_y, i_x] = 1 elif distance >= r_grain: M_psi[-1-i_y, i_x] = 0 # compute surface grains and water Surface_grain = np.sum(M_psi)/M_psi.size*dict_user['dim_domain']*dict_user['dim_domain'] Surface_water = dict_user['dim_domain']*dict_user['dim_domain'] - Surface_grain # compute ratio m_H20_m_cement = (Surface_water*dict_user['rho_water'])/(Surface_grain*dict_user['rho_g']) # print result print() print(len(L_radius_grains),'grains inserted') print('psd:', round(np.mean(L_radius_grains),1),'(mean)', round(np.min(L_radius_grains),1),'(min)', round(np.max(L_radius_grains),1),'(max)') print('m_H20/m_cement:', round(m_H20_m_cement,2),'/',dict_user['w_g_target'],'targetted') # Compute phi n_seed = dict_user['n_seed'] for i_seed in range(n_seed): i_try = 0 seed_created = False while not seed_created and i_try < 500: i_try = i_try + 1 # generate a seed i_x_seed = random.randint(0, len(L_x)-1) i_y_seed = random.randint(0, len(L_y)-1) center_seed = np.array([L_x[i_x_seed], L_y[i_y_seed]]) r_seed = dict_user['w_int']+dict_user['d_mesh'] # verify the node is not in a cement source # and not far from a source if M_psi[-1-i_y_seed, i_x_seed] != 1: close_seed = False for i_grain in range(len(L_pos_grains_real_virtual)): d_seed_grain = np.linalg.norm(center_seed-L_pos_grains_real_virtual[i_grain]) if d_seed_grain < L_radius_grains_real_virtual[i_grain]+2*r_seed: close_seed = True if close_seed: seed_created = True # compute the number of node (depending on the radius) n_nodes = 2*int(r_seed/(L_x[1]-L_x[0])) for i_x in range(max(0,i_x_seed-n_nodes),min(i_x_seed+n_nodes+1,len(L_x))): for i_y in range(max(0,i_y_seed-n_nodes),min(i_y_seed+n_nodes+1,len(L_y))): x = L_x[i_x] y = L_y[i_y] Point = np.array([x, y]) distance = np.linalg.norm(Point-center_seed) # Update map psi if M_phi[-1-i_y, i_x] == 0 : # do not erase data already written if distance <= r_seed: M_phi[-1-i_y, i_x] = 1 elif distance >= r_seed: M_phi[-1-i_y, i_x] = 0 # print psi/phi map M_phi_psi = M_psi + 2*M_phi fig, (ax1) = plt.subplots(1,1,figsize=(16,9)) title_fontsize = 30 im = ax1.imshow(M_phi_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]), vmax=2) cbar = fig.colorbar(im, ax=ax1) cbar.set_ticks(ticks=[0, 1, 2], labels=['Pore', 'Source', 'C-S-H']) fig.tight_layout() fig.savefig('png/IC_one_map.png') plt.close(fig) # adapt maps M_psi = M_psi - 0.5 if n_seed > 0: M_phi = M_phi - 0.5 # compute the signed distance functions sd_psi = skfmm.distance(M_psi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]])) if n_seed > 0: sd_phi = skfmm.distance(M_phi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]])) # compute the phase field variables for i_x in range(len(L_x)): for i_y in range(len(L_y)): # phi if n_seed > 0: if sd_phi[i_y, i_x] > dict_user['w_int']/2: # inside the grain M_phi[i_y, i_x] = 1 elif sd_phi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain M_phi[i_y, i_x] = 0 else : # in the interface M_phi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_phi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int']))) # psi if sd_psi[i_y, i_x] > dict_user['w_int']/2: # inside the grain M_psi[i_y, i_x] = 1 elif sd_psi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain M_psi[i_y, i_x] = 0 else : # in the interface M_psi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_psi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int']))) # result print() print('Mean value of psi:', round(np.sum(M_psi)/M_psi.size,2)) print('Mean value of phi:', round(np.sum(M_phi)/M_phi.size,2)) # Plot maps fig, ((ax1),(ax2),(ax3)) = plt.subplots(3,1,figsize=(9,25)) # parameters title_fontsize = 30 # psi im = ax1.imshow(M_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax1) ax1.set_title(r'Map of $\psi$',fontsize = title_fontsize) # phi im = ax2.imshow(M_phi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax2) ax2.set_title(r'Map of $\phi$',fontsize = title_fontsize) # c im = ax3.imshow(M_c, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax3) ax3.set_title(r'Map of c',fontsize = title_fontsize) fig.savefig('png/IC.png') plt.close(fig) # save in dicts dict_sample['L_x'] = L_x dict_sample['L_y'] = L_y dict_sample['M_psi'] = M_psi dict_sample['M_phi'] = M_phi dict_sample['M_c'] = M_c # Write data file_to_write_psi = open('txt/psi.txt','w') file_to_write_phi = open('txt/phi.txt','w') file_to_write_c = open('txt/c.txt','w') # x file_to_write_psi.write('AXIS X\n') file_to_write_phi.write('AXIS X\n') file_to_write_c.write('AXIS X\n') line = '' for x in dict_sample['L_x']: line = line + str(x)+ ' ' line = line + '\n' file_to_write_psi.write(line) file_to_write_phi.write(line) file_to_write_c.write(line) # y file_to_write_psi.write('AXIS Y\n') file_to_write_phi.write('AXIS Y\n') file_to_write_c.write('AXIS Y\n') line = '' for y in dict_sample['L_y']: line = line + str(y)+ ' ' line = line + '\n' file_to_write_psi.write(line) file_to_write_phi.write(line) file_to_write_c.write(line) # data file_to_write_psi.write('DATA\n') file_to_write_phi.write('DATA\n') file_to_write_c.write('DATA\n') for l in range(len(dict_sample['L_y'])): for c in range(len(dict_sample['L_x'])): file_to_write_psi.write(str(M_psi[-1-l][c])+'\n') file_to_write_phi.write(str(M_phi[-1-l][c])+'\n') file_to_write_c.write(str(M_c[-1-l][c])+'\n') # close file_to_write_psi.close() file_to_write_phi.close() file_to_write_c.close()
def Insert_Powder_Seed()
-
Insert n_grains grains in the domain. The grains are circle defined by a radius (uniform distribution). The position of the grains is randomly set, overlap between particules is allowed. A ratio of water mass / cement mass is targetted.
Map of phi, psi and c are generated.
Expand source code
def Insert_Powder_Seed(dict_sample, dict_user): ''' Insert n_grains grains in the domain. The grains are circle defined by a radius (uniform distribution). The position of the grains is randomly set, overlap between particules is allowed. A ratio of water mass / cement mass is targetted. Map of phi, psi and c are generated. ''' # Initialize the arrays M_psi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh'])) M_phi = np.zeros((dict_user['n_mesh'],dict_user['n_mesh'])) M_c = dict_user['C_eq_phi']*np.ones((dict_user['n_mesh'],dict_user['n_mesh'])) # Initialize the mesh lists L_x = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh']) L_y = np.linspace(-dict_user['dim_domain']/2, dict_user['dim_domain']/2, dict_user['n_mesh']) # Insert grains m_H20_m_cement = 2*dict_user['w_g_target'] while m_H20_m_cement > dict_user['w_g_target']: # Random radius of the grain r_grain = max(dict_user['R']*(1+dict_user['R_var']*(random.random()-0.5)*2), dict_user['d_mesh']*5) # Random position of the grain center x_grain = (dict_user['dim_domain']/2+r_grain)*(random.random()-0.5)*2 y_grain = (dict_user['dim_domain']/2+r_grain)*(random.random()-0.5)*2 Center_grain = np.array([x_grain, y_grain]) # find the nearest node of the center L_search = list(abs(np.array(L_x-x_grain))) i_x_center = L_search.index(min(L_search)) L_search = list(abs(np.array(L_y-y_grain))) i_y_center = L_search.index(min(L_search)) # compute the number of node (depending on the radius) n_nodes = int(r_grain/(L_x[1]-L_x[0]))+15 for i_x in range(max(0,i_x_center-n_nodes),min(i_x_center+n_nodes+1,len(L_x))): for i_y in range(max(0,i_y_center-n_nodes),min(i_y_center+n_nodes+1,len(L_y))): x = L_x[i_x] y = L_y[i_y] Point = np.array([x, y]) distance = np.linalg.norm(Point-Center_grain) # Update map psi if distance <= r_grain : M_psi[-1-i_y, i_x] = 1 # compute the ratio water mass/cement mass Surface_grain = np.sum(M_psi)*(L_x[1]-L_x[0])*(L_y[1]-L_y[0]) Surface_water = dict_user['dim_domain']*dict_user['dim_domain'] - Surface_grain m_H20_m_cement = Surface_water*dict_user['rho_water']/(Surface_grain*dict_user['rho_g']) # output print('Compute IC:',round(m_H20_m_cement,2),'/',dict_user['w_g_target'],'targetted') # Compute phi n_seed = dict_user['n_seed'] for i_seed in range(n_seed): i_try = 0 seed_created = False while not seed_created and i_try < 100: i_try = i_try + 1 # generate a seed i_x_seed = random.randint(0, len(L_x)-1) i_y_seed = random.randint(0, len(L_y)-1) center_seed = np.array([L_x[i_x_seed], L_y[i_y_seed]]) # verify the node is not in a cement source if M_psi[-1-i_y_seed, i_x_seed] != 1: seed_created = True # generate the seed r_seed = 1.3*dict_user['w_int'] # compute the number of node (depending on the radius) n_nodes = int(r_seed/(L_x[1]-L_x[0]))+4 for i_x in range(max(0,i_x_seed-n_nodes),min(i_x_seed+n_nodes+1,len(L_x))): for i_y in range(max(0,i_y_seed-n_nodes),min(i_y_seed+n_nodes+1,len(L_y))): x = L_x[i_x] y = L_y[i_y] Point = np.array([x, y]) distance = np.linalg.norm(Point-center_seed) # Update map psi if M_phi[-1-i_y, i_x] == 0 : # do not erase data already written if distance <= r_seed: M_phi[-1-i_y, i_x] = 1 elif distance >= r_seed: M_phi[-1-i_y, i_x] = 0 # print psi/phi map M_phi_psi = M_psi + 2*M_phi fig, (ax1) = plt.subplots(1,1,figsize=(16,9)) title_fontsize = 30 im = ax1.imshow(M_phi_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1]), vmax=2) cbar = fig.colorbar(im, ax=ax1) cbar.set_ticks(ticks=[0, 1, 2], labels=['Pore', 'Source', 'C-S-H']) fig.tight_layout() fig.savefig('png/IC_one_map.png') plt.close(fig) # adapt maps M_psi = M_psi - 0.5 M_phi = M_phi - 0.5 # compute the signed distance functions sd_phi = skfmm.distance(M_phi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]])) sd_psi = skfmm.distance(M_psi, dx = np.array([L_x[1]-L_x[0],L_y[1]-L_y[0]])) # compute the phase field variables for i_x in range(len(L_x)): for i_y in range(len(L_y)): # phi if sd_phi[i_y, i_x] > dict_user['w_int']/2: # inside the grain M_phi[i_y, i_x] = 1 elif sd_phi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain M_phi[i_y, i_x] = 0 else : # in the interface M_phi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_phi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int']))) # psi if sd_psi[i_y, i_x] > dict_user['w_int']/2: # inside the grain M_psi[i_y, i_x] = 1 elif sd_psi[i_y, i_x] < -dict_user['w_int']/2: # outside the grain M_psi[i_y, i_x] = 0 else : # in the interface M_psi[i_y, i_x] = 0.5*(1+math.cos(math.pi*(-sd_psi[i_y, i_x]+dict_user['w_int']/2)/(dict_user['w_int']))) # result print() print('Mean value of psi:', round(np.sum(M_psi)/M_psi.size,2)) print('Mean value of phi:', round(np.sum(M_phi)/M_phi.size,2)) # Plot maps fig, ((ax1),(ax2),(ax3)) = plt.subplots(3,1,figsize=(9,25)) # parameters title_fontsize = 30 # psi im = ax1.imshow(M_psi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax1) ax1.set_title(r'Map of $\psi$',fontsize = title_fontsize) # phi im = ax2.imshow(M_phi, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax2) ax2.set_title(r'Map of $\phi$',fontsize = title_fontsize) # c im = ax3.imshow(M_c, interpolation = 'nearest', extent=(L_x[0],L_x[-1],L_y[0],L_y[-1])) fig.colorbar(im, ax=ax3) ax3.set_title(r'Map of c',fontsize = title_fontsize) fig.savefig('png/IC.png') plt.close(fig) # save in dicts dict_sample['L_x'] = L_x dict_sample['L_y'] = L_y dict_sample['M_psi'] = M_psi dict_sample['M_phi'] = M_phi dict_sample['M_c'] = M_c # Write data file_to_write_psi = open('txt/psi.txt','w') file_to_write_phi = open('txt/phi.txt','w') file_to_write_c = open('txt/c.txt','w') # x file_to_write_psi.write('AXIS X\n') file_to_write_phi.write('AXIS X\n') file_to_write_c.write('AXIS X\n') line = '' for x in dict_sample['L_x']: line = line + str(x)+ ' ' line = line + '\n' file_to_write_psi.write(line) file_to_write_phi.write(line) file_to_write_c.write(line) # y file_to_write_psi.write('AXIS Y\n') file_to_write_phi.write('AXIS Y\n') file_to_write_c.write('AXIS Y\n') line = '' for y in dict_sample['L_y']: line = line + str(y)+ ' ' line = line + '\n' file_to_write_psi.write(line) file_to_write_phi.write(line) file_to_write_c.write(line) # data file_to_write_psi.write('DATA\n') file_to_write_phi.write('DATA\n') file_to_write_c.write('DATA\n') for l in range(len(dict_sample['L_y'])): for c in range(len(dict_sample['L_x'])): file_to_write_psi.write(str(M_psi[-1-l][c])+'\n') file_to_write_phi.write(str(M_phi[-1-l][c])+'\n') file_to_write_c.write(str(M_c[-1-l][c])+'\n') # close file_to_write_psi.close() file_to_write_phi.close() file_to_write_c.close()