基于损伤模型的硫酸根离子侵蚀混凝土细观数值模型。 有相对应完整的教学视频。
混凝土遇到硫酸盐侵蚀这事儿,工程界头疼几十年了。今天咱们直接上硬货,用Python手搓一个细观尺度的损伤模型,看看硫酸根离子是怎么在混凝土内部搞事情的。先别急着关页面,代码比论文有意思多了(手动狗头)
先来个暴力美学——生成混凝土细观结构。咱们用蒙特卡洛方法随机投放骨料:
import numpy as np from scipy.spatial import distance def generate_aggregates(width, height, radius_range): aggregates = [] attempts = 0 while len(aggregates) < 50 and attempts < 1000: x = np.random.uniform(0, width) y = np.random.uniform(0, height) r = np.random.uniform(*radius_range) collision = False for (ax, ay, ar) in aggregates: if distance.euclidean((x,y), (ax,ay)) < (r + ar)*1.2: collision = True break if not collision: aggregates.append((x, y, r)) return aggregates这段代码就像在混凝土里撒豆子,撒的时候还得保证豆子之间保持安全距离。那个1.2的系数是给界面过渡区(ITZ)留的位置,玩过俄罗斯方块的都知道不预留空间迟早game over。
离子扩散得用有限差分法,但咱们加点损伤耦合的骚操作:
def sulfate_diffusion(grid, damage, D0=0.01, threshold=0.3): new_grid = np.copy(grid) for i in range(1, grid.shape[0]-1): for j in range(1, grid.shape[1]-1): # 损伤影响扩散系数 effective_D = D0 * (1 - damage[i,j])**2 flux = (grid[i+1,j] + grid[i-1,j] + grid[i,j+1] + grid[i,j-1] - 4*grid[i,j]) new_grid[i,j] = grid[i,j] + effective_D * flux # 浓度超阈值触发结晶膨胀 if new_grid[i,j] > threshold: damage[i,j] += 0.05 * (new_grid[i,j] - threshold) return np.clip(new_grid, 0, 1), np.clip(damage, 0, 1)这里有个魔鬼细节:损伤不仅影响扩散速率,高浓度硫酸盐还会反过来加速损伤。就像渣男劈腿,出轨次数越多越容易暴露,暴露了反而更肆无忌惮(奇怪的比喻增加了)
可视化部分必须整点花活,用pygame实时展示侵蚀过程:
import pygame from matplotlib import cm def render(surface, concentration, damage): colormap = cm.get_cmap('plasma') for i in range(concentration.shape[0]): for j in range(concentration.shape[1]): # 浓度用暖色调,损伤用冷色调 conc_color = colormap(concentration[i,j])[:3] dam_color = (0, damage[i,j]*0.8, damage[i,j]) blend = [x*0.6 + y*0.4 for x,y in zip(conc_color, dam_color)] pygame.draw.rect(surface, [int(255*c) for c in blend], (i*4, j*4, 4, 4))跑起来之后你会看到红色硫酸盐前锋像岩浆一样推进,后面跟着蓝汪汪的损伤区域,比吃鸡的毒圈还刺激。教学视频里我还埋了个彩蛋——按空格键能暂停观察微裂纹的分形结构,绝对治愈强迫症。
最后说点人话:这个模型虽然简化了真实化学过程,但胜在能直观看到损伤和扩散的相爱相杀。下次工地老哥再说"混凝土烂根",你可以掏出模拟结果告诉他:"兄dei,是ITZ区域先动的手!"