MULTI-2D:压强、密度、网格分布图的Python实现

上一期,我们介绍了MULTI-2D的基本数据结构,并根据此基本数据结构使用Python编写了MULTI-2D的数据读取脚本,本期我们将根据读取到的MULTI-2D计算数据,利用Python绘制一些必要的可视化结果。

上一期传送门:

下面我们将以MULTI-2D自带的算例 D51_H_Implo 为例对数据读取脚本"multi2d.py"编程修改。

一、针对数据读取部分的修改说明

现在让我们将上一节中跑出来的 D51_H_Implo 的数据结果回顾一下:数据文件(形如 0 )、.d类型文件(形如0.d),以及我们修改源代码输出的拓扑信息文件t.data.除此之外,还包括很多其他杂七杂八的文件,我们暂时用不到。以上这些文件都被存储在文件夹D51_H_Implo内。

现在让我们打开Python,将工作目录调整至包含文件夹D51_H_Implo的目录,开始我们的编程。

首先让我们打开.d类型文件(随便打开一个就可以,我打开的是1.01e-08.d),如图1:

图1 1.01e-08.d内容

文件里从第二行开始存储了输出的变量是啥,以及网格节点数,可以看到,一共有8个变量,按照顺序依次是:rho, x, y, vx, vy, P, TC, T.那么我们需要在读取数据的函数中按照这个这个顺序修改一下代码,如下:

import math
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import struct
import sys
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
#from scipy.fftpack import fft  #用于傅里叶分析
from scipy.fftpack import fft,fftshift
from matplotlib.pylab import mpl
import os
import matplotlib.ticker as ticker
#from sympy.vector import CoordSys3D,Del   #用于求场的梯度
#定义函数read_multi01,该函数作用是返回'file01.d'文件中的nrho,nfrac1,
#nfrac2,nfrac3,nx,ny,nvx,nvy,nP,nTC,nT,nmid,nrays,nDM,nDV,nTR,nlambda.
def read_multi01(filename):
    file01 = open(filename,'r')   #读取文件存入file01

    line = file01.readline()      #读取第一行存入line,返回'MF01\n'
    
    line = file01.readline()      #读取第二行存入line,例如,返回'rho     1   48362\n'
    tmp = line.split()            #将line按照空格拆分,例如,得到['rho', '1', '48362']列表记为tmp
    nrho = int(tmp[2])            #第三个元素记为nrho
    
    line = file01.readline()
    tmp = line.split()
    nx = int(tmp[2])
    
    line = file01.readline()
    tmp = line.split()
    ny = int(tmp[2])
    
    line = file01.readline()
    tmp = line.split()
    nvx = int(tmp[2])
    
    line = file01.readline()
    tmp = line.split()
    nvy = int(tmp[2])
    
    line = file01.readline()
    tmp = line.split()
    nP = int(tmp[2])
    
    line = file01.readline()
    tmp = line.split()
    nTC = int(tmp[2])
    
    line = file01.readline()
    tmp = line.split()
    nT = int(tmp[2])
    
    file01.close()
    return(nrho,nx,ny,nvx,nvy,nP,nTC,nT)
#定义函数read_multi02,读取file02(数据文件例如6e-10),根据数据文件读取出
#rho,frac1,frac2,frac3,x,y,vx,vy,P,TC,T,mid,rays,DM,DV,TR,lamb
    
def read_multi02(filename,size):
    file02 = open(filename,'rb')

    line = file02.read(4)
    real = struct.unpack('4c',line)   #对二进制数据进行解析
    
    nrho = size[0]
    nx = size[1]
    ny = size[2]
    nvx = size[3]
    nvy = size[4]
    nP = size[5]
    nTC = size[6]
    nT = size[7]
    
    rho   = struct.unpack('f'*size[0] ,file02.read(4*size[0]))
    x     = struct.unpack('f'*size[1] ,file02.read(4*size[1]))
    y     = struct.unpack('f'*size[2] ,file02.read(4*size[2]))
    vx    = struct.unpack('f'*size[3] ,file02.read(4*size[3]))
    vy    = struct.unpack('f'*size[4] ,file02.read(4*size[4]))
    P     = struct.unpack('f'*size[5] ,file02.read(4*size[5]))
    TC    = struct.unpack('f'*size[6] ,file02.read(4*size[6]))
    T     = struct.unpack('f'*size[7],file02.read(4*size[7]))
    file02.close()
    #return(0, 1     2     3    4 5 6  7  8 9  10  11   12  13 14 15  16
    return(rho,x,y,vx,vy,P,TC, T)
#定义函数read_malla,读取t.data文件,获得网格信息,n_node指节点数,存在.d文件的frac3里
def read_malla(filename,n_node):
    mallafile = open(filename,'r')

    node_t = []
    for i in range(n_node):
        ia = int(mallafile.readline())-1
        ib = int(mallafile.readline())-1
        ic = int(mallafile.readline())-1
        node_t.append([ia,ib,ic])
        
    mallafile.close()
    return(node_t)

上面三个函数分别读取了三种类型的文件,需要注意的是,函数read_multi01()和函数read_multi02()里面读取的行数都是根据我们刚刚查看的图1的内容决定的,这里一共八个变量,所以按照python的索引顺序我们就从0依次索引到7,将这些数据读取出来。

像上节一样,我们还是将一些常用函数定义下来,以备不时之需:

# get the position of each triangle element
def get_nodex(x,y,node_t,n_node):
    xnode = []
    ynode = []
    for i in range(n_node):
        xtmp = (x[node_t[i][0]] + x[node_t[i][1]] + x[node_t[i][2]])/3.0
        ytmp = (y[node_t[i][0]] + y[node_t[i][1]] + y[node_t[i][2]])/3.0
        xnode.append(xtmp)
        ynode.append(ytmp)
    return(xnode,ynode)

#get the  volume of each triangle element
def get_volume(x,y,node_t,n_node):
    volumelist = []
    for i in range(n_node):
        x1 = x[node_t[i][0]]
        y1 = y[node_t[i][0]]
        x2 = x[node_t[i][1]]
        y2 = y[node_t[i][1]]
        x3 = x[node_t[i][2]]
        y3 = y[node_t[i][2]]
        r = (y1+y2+y3)/3.0
        # 计算三边长度
        a = math.sqrt((x1 - x2)**2 + (y1 - y2)**2)
        b = math.sqrt((x2 - x3)**2 + (y2 - y3)**2)
        c = math.sqrt((x1 - x3)**2 + (y1 - y3)**2)
        
        # 计算半周长
        p = (a + b + c) / 2
        
        # 计算面积
        area = math.sqrt(p * (p - a) * (p - b) * (p - c))
        #print("三角形面积为:", area)
        #计算体积
        volume = (3.1415926/3)*(y1 + y2 +y3 ) * ((x2 -x1)*(y3- y1) - (x3 - x1)*(y2 - y1))
        volumelist.append(volume)
        #print("三角形体积为:",volume)
    return volumelist
    
# change cell data to point data
def cell2point(fdata,node_t,npoint,nnode):
    pdata = [0]*npoint
    pcount = [0]*npoint
    for i in range(nnode):
        pdata[node_t[i][0]] += fdata[i]
        pcount[node_t[i][0]] += 1
        pdata[node_t[i][1]] += fdata[i]
        pcount[node_t[i][1]] += 1
        pdata[node_t[i][2]] += fdata[i]
        pcount[node_t[i][2]] += 1
    for i in range(npoint):
        #print("i=%d pcount=%d" % (i,pcount[i]))
        if pcount[i] > 0 :
            pdata[i] = pdata[i]/pcount[i]
    return pdata

二、单张分布图绘图函数和主程序编写

我们首先编写用于绘制单张分布图的函数,为了使这个函数可以被反复使用,设置形参时要把必要信息都放进去,比如时刻、变量名、有无网格等等,如下:

def plot_distribution(quantity,size,data,nodet,title,output_path,grid = 0):
    # 设置中文字体
    matplotlib.rcParams['font.sans-serif'] = ['SimHei']
    matplotlib.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    if quantity == 'P' or 'Pressure':
        quantity_id = 5
    if quantity == 'rho':
        quantity_id = 0
    x = data[1];y = data[2] 
    nnode = size[0]; npoint = size[7]      
    quantity_data = cell2point(data[quantity_id],nodet,npoint,nnode) 
    
    
    plt.figure(dpi=120,figsize=(10,4))
    triangulation = tri.Triangulation(x,y,nodet)
    
#    pcm = plt.tripcolor(triangulation,quantity_data,
#                       norm=matplotlib.colors.LogNorm(),#vmin = 1e7,vmax = 1e9),
#                       cmap='rainbow', shading='flat')
#    plt.colorbar(pcm, extend='max')#,format='%d'
    
    if grid == 1:
        # 绘制三角网格的网格线
        print('Grid open!')
        plt.triplot(x,y, color='b',linewidth=0.4)
#        plt.xlim(-0.1,0.1)
#        plt.ylim(0,0.1)
    plt.title(title)
    plt.xlabel('X /cm')
    plt.ylabel('Y /cm')
#    plt.xlim(min(x),max(x))
#    plt.ylim(min(y),max(y))
    if not os.path.exists(output_path+'\\'+quantity):    
        os.makedirs(output_path+'\\'+quantity)
    plt.savefig(output_path+'\\'+quantity+'\\'+title+'.png')

在使用时,我们可以通过调节quantitity的内容绘制不同的图,通过设置title的传入内容指定图片的标题,size和data分别是我们的两个函数read_multi01()和read_multi02()的返回结果。

下面,我们编写主程序完成数据的读取和可视化,代码如下:

input_path ='D51_H_Implo'
time = '5e-09'
output_path = '绘图文件夹'

filename01 = input_path+'\\'+time+'.d'
size = read_multi01(filename01)  
filename02 = input_path+'\\'+time
data = read_multi02(filename02,size) 
nodet = read_malla(input_path+'\\'+'t.data',size[0])
quantity = ''
title = input_path+' '+'Var='+quantity + ' ' +'time='+time
title = '网格设置展示:5e-09'
#
plot_distribution(quantity,size,data,nodet,title,output_path,grid = 1)

上面的代码中有一些变量需要说明,1. input_path指定了要读取的文件夹,可以根据需求自行更改;2.time指定了要读取的时刻,可以根据需求自行更改; 3. output_path制定了要输出的文件夹名称,该文件夹需要提前创建; 4. title部分复写了两次,第一次是默认设置,会在标题部分标记出当前算例、物理量、时间,下面的那一次是根据具体需求写的,比如目前上面的代码直接执行将会绘制5e-09时刻时的网格分布图(grid=1),如果不需要可以直接注释掉。

直接执行上述代码,我们将看到一张网格分布,如图2,这里在绘制网格分布的时候,我们采用了三角剖分算法,之所以能这样画,是因为我们拿到了MULTI-2D输出的网格和节点的位置信息。

图2 5e-09时的网格分布

除此之外,我们可以直接修改quantity的内容为P,并将网格关掉,把plot_distribution()中pcm到if grid那一行之间的注释都取消掉,绘制压强分布图,修改后的代码如下,图见图3:

def plot_distribution(quantity,size,data,nodet,title,output_path,grid = 0):
    # 设置中文字体
    matplotlib.rcParams['font.sans-serif'] = ['SimHei']
    matplotlib.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    if quantity == 'P' or 'Pressure':
        quantity_id = 5
    if quantity == 'rho':
        quantity_id = 0
    x = data[1];y = data[2] 
    nnode = size[0]; npoint = size[7]      
    quantity_data = cell2point(data[quantity_id],nodet,npoint,nnode) 
    
    
    plt.figure(dpi=120,figsize=(10,4))
    triangulation = tri.Triangulation(x,y,nodet)
    
    pcm = plt.tripcolor(triangulation,quantity_data,
                       norm=matplotlib.colors.LogNorm(),#vmin = 1e7,vmax = 1e9),
                       cmap='rainbow', shading='flat')
    plt.colorbar(pcm, extend='max')#,format='%d'
    
    if grid == 1:
        # 绘制三角网格的网格线
        print('Grid open!')
        plt.triplot(x,y, color='b',linewidth=0.4)
#        plt.xlim(-0.1,0.1)
#        plt.ylim(0,0.1)
    plt.title(title)
    plt.xlabel('X /cm')
    plt.ylabel('Y /cm')
#    plt.xlim(min(x),max(x))
#    plt.ylim(min(y),max(y))
    if not os.path.exists(output_path+'\\'+quantity):    
        os.makedirs(output_path+'\\'+quantity)
    plt.savefig(output_path+'\\'+quantity+'\\'+title+'.png')

#以下为主程序

input_path ='D51_H_Implo'
time = '5e-09'
output_path = '绘图文件夹'

filename01 = input_path+'\\'+time+'.d'
size = read_multi01(filename01)  
filename02 = input_path+'\\'+time
data = read_multi02(filename02,size) 
nodet = read_malla(input_path+'\\'+'t.data',size[0])
quantity = 'P'
title = input_path+' '+'Var='+quantity + ' ' +'time='+time
#title = '网格设置展示:5e-09'
#
plot_distribution(quantity,size,data,nodet,title,output_path,grid = 0)

图3 5e-09时刻压强分布图

直接将quantity改为’rho’,绘制密度分布图如下:

图4 5e-09时刻密度分布图

至此,我们基本复现了MULTI-2D自带的可视化的软件的可视化功能,并且拥有更灵活的调整空间,下面我们针对MULTI-2D没有的功能进行完善。

三、组合子图的物理量分布函数和主程序编写

在论文中,我们往往要将物理量的分布图做成组合图,标记上子图(a)(b)©(d)以节省论文版面,这个功能无法用MULTI-2D的自带后处理软件直接实现,因此需要编程处理。为了将上面形成的分布图按照时刻的不同组合成一张新图,以体现物理量随时间的演化,我们编写了一个新的函数plot_Combination().该函数可以将四张不同的子图组合起来,并且你可以根据需要调整子图的格式(例如title,units,子图标签,刻度轴范围等),代码如下:

def plot_Combination(quantity,size1,data1,nodet1,size2,data2,nodet2,size3,data3,nodet3,
                     size4,data4,nodet4,title,output_path):
    # 设置中文字体
    matplotlib.rcParams['font.sans-serif'] = ['SimHei']
    matplotlib.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    if quantity == 'P' or 'Pressure':
        quantity_id = 5
        unit = 'Unit: dyn/cm^2' 
    if quantity == 'rho':
        quantity_id = 0
        unit = 'Unit: g/cm^3' #g/cm3

    lo_legend = (0.2,0.2)
    xlim = (0,0.22)
    ylim = (0,0.22)
    vmin = None
    vmax = None
    
    x1 = data1[1];y1 = data1[2] 
    nnode1 = size1[0]; npoint1 = size1[7]      
    quantity_data1 = cell2point(data1[quantity_id],nodet1,npoint1,nnode1) 
    
    x2 = data2[1];y2 = data2[2] 
    nnode2 = size2[0]; npoint2 = size2[7]      
    quantity_data2 = cell2point(data2[quantity_id],nodet2,npoint2,nnode2)
    
    x3 = data3[1];y3 = data3[2] 
    nnode3 = size3[0]; npoint3 = size3[7]      
    quantity_data3 = cell2point(data3[quantity_id],nodet3,npoint3,nnode3)
    
    x4 = data4[1];y4 = data4[2] 
    nnode4 = size4[0]; npoint4 = size4[7]      
    quantity_data4 = cell2point(data4[quantity_id],nodet4,npoint4,nnode4) 
    
    fig, axs = plt.subplots(2,2,dpi=150,subplot_kw={'aspect': 'equal'})       
    axs = axs.flatten()                             
    
    triangulation = tri.Triangulation(x1,y1,nodet1)
    
    pcm = axs[0].tripcolor(triangulation,quantity_data1,
                       norm=matplotlib.colors.LogNorm(vmin = vmin,vmax = vmax),
                       
                       cmap='rainbow', shading='flat')
    fig.colorbar(pcm,ax=axs[0], extend='max',shrink=0.7, pad=0.05,format='%.1f')
    axs[0].set_title(title[0], fontsize=8)
    axs[0].set_xlabel('X /cm')
    axs[0].set_ylabel('Y /cm')
    axs[0].text(lo_legend[0], lo_legend[1], '(a)', fontsize=12, ha='center', va='center')
#    axs[0].set_xlim(min(x1), max(x1))
#    axs[0].set_ylim(min(y1), max(y1))
    axs[0].set_xlim(xlim[0], xlim[1])
    axs[0].set_ylim(ylim[0], ylim[1])
    
    triangulation = tri.Triangulation(x2,y2,nodet2)
    
    pcm = axs[1].tripcolor(triangulation,quantity_data2,
                       norm=matplotlib.colors.LogNorm(vmin = vmin,vmax = vmax),#vmin = 1e7,vmax = 1e9),
                       
                       cmap='rainbow', shading='flat')
    fig.colorbar(pcm,ax=axs[1], extend='max',shrink=0.7, pad=0.05,format='%.1f')
    axs[1].set_title(title[1],fontsize=8)
    axs[1].set_xlabel('X /cm')
    axs[1].set_ylabel('Y /cm')
    axs[1].text(lo_legend[0], lo_legend[1], '(b)', fontsize=12, ha='center', va='center')
#    axs[1].set_xlim(min(x2), max(x2))
#    axs[1].set_ylim(min(y2), max(y2))
    axs[1].set_xlim(xlim[0], xlim[1])
    axs[1].set_ylim(ylim[0], ylim[1])
    
    
    triangulation = tri.Triangulation(x3,y3,nodet3)
    
    pcm = axs[2].tripcolor(triangulation,quantity_data3,
                       norm=matplotlib.colors.LogNorm(vmin = vmin,vmax = vmax),#vmin = 1e7,vmax = 1e9),
                       
                       cmap='rainbow', shading='flat')
    fig.colorbar(pcm,ax=axs[2], extend='max',shrink=0.7, pad=0.05,format='%.1f')
    axs[2].set_title(title[2],fontsize=8)
    axs[2].set_xlabel('X /cm')
    axs[2].set_ylabel('Y /cm')
    axs[2].text(lo_legend[0], lo_legend[1], '(c)', fontsize=12, ha='center', va='center')
   # axs[2].set_xlim(min(x3), max(x3))
    #axs[2].set_ylim(min(y3), max(y3))
    axs[2].set_xlim(xlim[0], xlim[1])
    axs[2].set_ylim(ylim[0], ylim[1])
    
    triangulation = tri.Triangulation(x4,y4,nodet4)
    
    pcm = axs[3].tripcolor(triangulation,quantity_data4,
                       norm=matplotlib.colors.LogNorm(vmin = vmin,vmax = vmax),#vmin = 1e7,vmax = 1e9),
                       
                       cmap='rainbow', shading='flat')
    fig.colorbar(pcm,ax=axs[3], extend='max',shrink=0.7, pad=0.05,format='%.2f')
    axs[3].set_title(title[3],fontsize=8)
    axs[3].set_xlabel('X /cm')
    axs[3].set_ylabel('Y /cm')
    axs[3].text(lo_legend[0],lo_legend[1], '(d)', fontsize=12, ha='center', va='center')
    axs[3].set_xlim(xlim[0], xlim[1])
    axs[3].set_ylim(ylim[0], ylim[1])
        # 手动设置轴的刻度位置和标签
#    for ax in axs.flatten():
#        xticks = [-5, -2.5,0,2.5,5]
#        yticks = [0,2.5,5]
#        ax.set_xticks(xticks)
#        ax.set_yticks(yticks)
#        ax.set_xticklabels(['a', 'b', 'c', 'd', 'e'])
#        ax.set_yticklabels(['zero', 'half', 'one'])
#      
    fig.text(0.8,0.95,unit,fontsize=8)
    #plt.suptitle('')
    # 调整子图之间的间距
    plt.subplots_adjust(wspace=0.1, hspace=0.5)
   # plt.tight_layout()

函数编写好之后,我们需要编写主程序执行,这里我们以密度分布为例,选取了四个时刻,绘制了四张子图,主程序如下:

size_li = []
data_li = []
nodet_li = []
title_li = []
time_li = ['9e-10','1.1e-09','8e-09','1.1e-08']
for i in time_li:
    #input_path = 'h-Au{}1-f'.format(i)
    #print(input_path)
    input_path = 'D51_H_Implo'
    time = i #'5.5e-09'
    output_path = '绘图文件夹'
    
    filename01 = input_path+'\\'+time+'.d'
    size = read_multi01(filename01)
    size_li.append(size)
    
    filename02 = input_path+'\\'+time
    data = read_multi02(filename02,size)
    data_li.append(data)
    
    nodet = read_malla(input_path+'\\'+'t.data',size[0])
    nodet_li.append(nodet)
    
    quantity = 'rho'
    title = input_path+' '+'Var='+quantity + ' ' +'time='+time
    title_li.append(title)

plot_Combination(quantity,size_li[0],data_li[0],nodet_li[0],
                 size_li[1],data_li[1],nodet_li[1],
                 size_li[2],data_li[2],nodet_li[2],
                 size_li[3],data_li[3],nodet_li[3],
                 title_li,output_path)    

我们这里使用了一个for循环来设置要读取的信息,直接执行上面的代码,输出结果如图5所示:

图5 不同时刻的密度分布

需要注意的是,很多时候我们为了对比更明显,会设置四张子图的colorbar取值范围相同,这个可以直接在plot_Combination()函数前半部分的vmin和vmax处设置,只需要写一个能囊括所有图的corlorbar取值的数值范围就可以了。压强分布也是一样的,修改quantity的值为’P’,可以直接得到压强分布如下:

图6 不同时刻压强分布

我们注意到由于上图中压强数值很大,corlorbar以整数方式显示会很长,所以需要修改一下代码中的colorbar显示方式,具体来说,将plot_Combination()函数中的四个

fig.colorbar(pcm,ax=axs[3], extend='max',shrink=0.7, pad=0.05,format='%.2f')

中的format='%.2f’删掉,这样重新执行代码,就会发现colorbar都以科学计数法显示了:

图7 不同时刻压强分布(corlorbar显示为科学计数法)

以上就是“MULTI-2D:压强、密度、网格分布图的Python实现”的全部内容,希望对你有所帮助。

关于Python技术储备

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

在这里插入图片描述

二、Python必备开发工具

img

三、Python视频合集

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

img

四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

img

五、Python练习题

检查学习结果。

img

六、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

img

最后祝大家天天进步!!

上面这份完整版的Python全套学习资料已经上传至CSDN官方,朋友如果需要可以直接微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】。

  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值