The reason why I am using
qw_z = qw_z.collapse()
V = FunctionSpace(mesh, ("Discontinuous Lagrange", 0))
Heat_Flux_z = Function(V, name='Heat_Flux_z')
Heat_Flux_z.x.array[:] = qw_z.x.array
is because I wanted the name Heat_Flux_z
to appear in Paraview instead of f
. But it’s simply cosmetic.
I am simulating heat spreading through a multilayered and multi-materials model imported from Gmsh. Regarding the plotting, I have first a function that extracts the temperature values_T
and heat flux values_q
density distribution and its maximum per layer in the domain (each layer has a different size and thickness):
def extract_values(T, qw_z, boundary, mesh, cell_tags, name_layers, PM_dict):
Tfs = T.function_space
coordinates = Tfs.tabulate_dof_coordinates()
eps = 1e-8
ln = name_layers.index(boundary)
H_list = np.array([PM_dict[l]['thickness'][0] for l in name_layers], dtype=float)
HL = H_list[:ln].sum()
BB = PM_dict[boundary]['BoundingBox']
X_list = np.array( [ np.array([bb.x1, bb.x2]).flatten() for bb in BB ] )
Y_list = np.array( [ np.array([bb.y1, bb.y2]).flatten() for bb in BB ] )
Xm_list = np.array( [ (bb.x1+bb.x2)/2. for bb in BB ] )
Ym_list = np.array( [ (bb.y1+bb.y2)/2. for bb in BB ] )
DX_list = np.array( [ (bb.x2-bb.x1) for bb in BB ] )
DY_list = np.array( [ (bb.y2-bb.y1) for bb in BB ] )
Xmin = X_list.flatten().min()
Xmax = X_list.flatten().max()
Ymin = Y_list.flatten().min()
Ymax = Y_list.flatten().max()
dx = 0.05 * Xmax
dy = 0.05 * Ymax
mXmin = coordinates[:,0] > Xmin + dx
mXmax = coordinates[:,0] < Xmax - dx
mYmin = coordinates[:,1] > Ymin + dy
mYmax = coordinates[:,1] < Ymax -dy
mZmax = abs(coordinates[:,2] - HL)<eps
if boundary == 'chip':
print("Chip level reached.")
HL = HL + H_list[-1]
if len(BB)==1:
print("BOUNDARY BOX USED")
d = np.where(mXmin & mXmax & mYmin & mYmax & mZmax)
else:
print("BOUNDARY BOX NOT USED")
d = np.where(mZmax)
xyz = coordinates[d]
values_q = qw_z.x.array[d]
values_T = T.x.array[d]
x = np.array([v[0] for v in xyz])
y = np.array([v[1] for v in xyz])
tdim = mesh.topology.dim
num_cells = mesh.topology.index_map(tdim).size_local
mesh = dolfinx.cpp.mesh.Mesh(mesh.comm, mesh.topology, mesh.geometry) # TODO remove with dolfinx 0.7.0
hmin = dolfinx.cpp.mesh.h(mesh, tdim, np.arange(num_cells, dtype=np.int32)).min()
Tmax = values_T.max()
imax = np.where(values_T==Tmax)
dm = np.where(values_T==Tmax)
qmax = values_q[dm].mean()
qavg = values_q.mean()
Tmax = values_T[dm].mean()
if 'PM_results' in PM_dict: # heater
dct = PM_dict['PM_results']
else: # Module
dct = PM_dict
if 'chip' in dct:
BB = dct['chip']['BoundingBox']
Xm_list = np.array( [ (bb.x1+bb.x2)/2. for bb in BB ] )
Ym_list = np.array( [ (bb.y1+bb.y2)/2. for bb in BB ] )
mXYc = (x!=x) # Initialize at False
for xc,yc in zip(Xm_list, Ym_list):
min_R = min(np.sqrt((x-xc)**2+(y-yc)**2))
mXYc = mXYc | (np.sqrt((x-xc)**2+(y-yc)**2)<=min_R)
ic = np.where(mXYc)
Tc_list = values_T[ic]
else:
Tc_list = Tmax
return x, y, values_q, values_T, qmax, qavg, Tmax, imax, Tc_list
Then the heat flux density map with its maximum is plotted for each layer with
def plot_map(x0, y0, f, imax, layer, name_layers ,PM_dict, saveDir, fn, unit=''):
print("Plot layer = ", layer)
# Map centering offsets
Dx = Dy = 0. #Chips and solder chip
if layer in PM_dict:
Dx = PM_dict[layer]['W'][0] / 2.
Dy = PM_dict[layer]['L'][0] / 2.
BB = PM_dict[layer]['BoundingBox']
ln = name_layers.index(layer)
# Center and convert to mm
x = (x0 + Dx) * 1e3
y = (y0 + Dy) * 1e3
xmax = max(x)
xmin = min(x)
ymax = max(y)
ymin = min(y)
xm = x[imax]
ym = y[imax]
fmax = f[imax]
fig = plt.figure()
for BBi in BB:
X_min = BBi.x1
X_max = BBi.x2
Y_min = BBi.y1
Y_max = BBi.y2
dx = 0
dy = 0
mX_min = (x0 >= (X_min+dx))
mX_max = (x0 <= (X_max-dx))
mY_min = (y0 >= (Y_min+dy))
mY_max = (y0 <= (Y_max-dy))
xbb = x[np.where(mX_min & mX_max & mY_min & mY_max)]
ybb = y[np.where(mX_min & mX_max & mY_min & mY_max)]
fbb = f[np.where(mX_min & mX_max & mY_min & mY_max)]
xbbmin = xbb.min()
xbbmax = xbb.max()
ybbmin = ybb.min()
ybbmax = ybb.max()
levels = np.linspace(min(fbb), max(fbb), 256)
points = (xbb, ybb)
grid_x, grid_y = np.mgrid[xbbmin:xbbmax:100j, ybbmin:ybbmax:100j]
grid = scipy.interpolate.griddata(points, fbb, (grid_x, grid_y), method='linear', fill_value=min(fbb))
plt.imshow(grid.T, extent=(xbbmin,xbbmax,ybbmin,ybbmax), origin='lower', cmap=plt.cm.jet)
plt.xticks([xbbmin,xbbmax])
plt.yticks([ybbmin,ybbmax])
cbar = plt.colorbar(pad=0.05)
cbar.set_label(unit)
plt.xlabel('x (mm)')
plt.ylabel('y (mm)')
plt.axis([xmin, xmax, ymin, ymax])
plt.axis('scaled')
plt.plot(xm, ym, 'w+', markersize=8)
plt.annotate(int(np.round(fmax,0)), (xm, ym), xycoords='data', xytext=(3,3), textcoords='offset points', size=7, color='w', **kwargs)
plt.savefig(saveDir+fn+'.pdf', format='pdf')
plt.close()
return 0
It’s far from being a minimal working example though.