拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Mumax3微磁学模拟从入门到参数优化:模板与避坑指南

Mumax3微磁学模拟从入门到参数优化:模板与避坑指南

做微磁学模拟的人应该都有过这种经历:文献里的结构看着并不复杂,材料参数也就那几个,结果自己一上手,Mumax3不是给你抛个NaN,就是磁矩怎么转都转不到目标状态。Mumax3是目前微磁学模拟里非常主流的GPU加速工具,相比OOMMF的CPU计算,它在脚本书写、批量扫描和大网格模拟上有明显优势,我自己主要拿它做磁性纳米结构里的磁涡旋、磁畴壁和斯格明子动力学。这篇内容准备分享一套我从基础设置到材料参数优化一直在用的Mumax3代码模板,同时把单位、网格、交换长度这些“新手重灾区”一次性讲清楚。内容更适合已经有最小模拟经验、正准备系统化调整材料参数的研究生和工程师,当然刚入门但愿意啃代码的人也能跟着跑完一遍。

1. Mumax3到底解决什么问题,为什么值得花时间学

1.1 微磁学模拟的核心逻辑

微磁学模拟说白了就是求解微磁学中的Landau-Lifshitz-Gilbert(LLG)方程,磁矩在有效场作用下进动、弛豫,最终达到平衡态或稳定动力学状态。有效场里包含交换场、退磁场、外磁场、各向异性场,如果做自旋电子学还得加上自旋转移矩、自旋轨道矩这些贡献。Mumax3就是把这些场和力矩全部集成好的有限差分求解器,你用脚本定义网格、材料、初始磁矩和外场,它自动解方程,给出磁矩随时间的演化。

这相当于你把“样品”在电脑里建出来,然后“做实验”:加磁场、看响应、扫参数、提取曲线。对于磁性随机存储器、磁传感器、赛道存储器这类器件设计,这种数值实验能提前暴露很多问题,省下大量流片和实验成本。

1.2 为什么是Mumax3而不是OOMMF或Nmag

OOMMF是学术界的老牌工具,稳定,文档全,但它主要跑CPU,网格一大就非常慢。Nmag的脚本灵活但上手门槛不低。Mumax3选择把计算放到GPU上,CUDA加速效果明显,很多原本要跑一整天的模型,换成Mumax3之后可能半小时就出结果。更重要的是Mumax3的脚本语言非常贴近“实验记录”思维,变量、循环、字段操作都直白,批量扫描时我可以直接在外部生成无数个mx3脚本扔给GPU跑,这个流程对参数优化来说太友好了。

当然,Mumax3也不是没有缺点。它是有限差分方法,网格和样品边界都是矩形阶梯,复杂曲面形状需要靠足够细的网格去逼近。但绝大多数纳米磁性结构和薄膜器件都是接近长方体或圆柱形状,阶梯近似可以接受。这个权衡我认为是值得的。

2. 一套能直接跑的基础代码模板

2.1 写脚本前先搞明白的三件事:网格、单位、几何

任何Mumax3脚本,开头三件事必须先理顺:网格划分、单位制、几何形状。

网格划分就是决定仿真区域用多少个有限差分元胞。Mumax3里有两个关键命令,setgridsize(Nx, Ny, Nz)设置三个方向的元胞数量,setcellsize(dx, dy, dz)设置每个元胞的物理尺寸。仿真区域总尺寸就是两者逐项相乘。举个例子,Nx=256、Ny=128、Nz=1,cell尺寸是2nm、2nm、5nm,那么样品就是512nm乘256nm的一块厚度5nm的薄膜。

单位制上Mumax3全部走国际单位制。饱和磁化强度Ms用A/m,交换刚度Aex用J/m,各向异性常数Ku1用J/m³,外加磁场Bext用T(特斯拉),时间t用秒。很多人第一次都会在这里翻车,尤其是把外加磁场的单位混淆成A/m,或者把Ms直接填成文献里的emu/cm³不去换算。这个问题后面我还会反复强调。

几何形状用setgeom定义。最简单的矩形是rect(512e-9, 256e-9),Mumax3会根据网格自动把它转成对应的磁矩掩模。几何尺寸必须和网格设置对应,否则会出现“尺寸对不上,内部还留了空隙”的尴尬情况。

2.2 最小可运行模板:复制改参数就能用

下面这套模板是我平时常用的起点,包含了网格、几何、材料、初始磁矩、外场、输出和求解设置,直接存成mx3文件就能运行:

// ===== 1. 网格设置 ===== Nx := 256 Ny := 128 Nz := 1 dx := 2e-9 dy := 2e-9 dz := 5e-9 setgridsize(Nx, Ny, Nz) setcellsize(dx, dy, dz) // ===== 2. 几何形状 ===== setgeom(rect(512e-9, 256e-9)) // ===== 3. 材料参数 ===== Ms := 800e3 // 饱和磁化强度,A/m Aex := 1.3e-11 // 交换刚度,J/m alpha := 0.01 // 阻尼系数,无单位 Ku1 := 0.0 // 单轴各向异性常数,J/m^3 anisU := vector(0, 0, 1) // 各向异性轴方向 // ===== 4. 初始磁矩与外场 ===== m = uniform(1, 0, 0.1) // 初始磁矩大致指向 x 方向 Bext = vector(0, 0, 0) // 外磁场,单位 T // ===== 5. 输出设置 ===== tableadd(Bext) tableadd(m) tableadd(E) autosave(m, 0.5e-12) // ===== 6. 求解设置 ===== MaxDt := 1e-13 // 限制最大时间步,防止发散 run(1e-9) save(m)

这段模板别看简单,已经足够做很多基础模拟了:只要改材料参数、几何、外场,就可以跑磁化动力学、磁滞回线、涡旋弛豫等常见问题。我会在下面逐段拆一下,说明每个参数实际影响什么。

2.3 模板逐段拆解:从网格到求解器

网格设置为什么要放在最前面?因为后续的几何、交换长度校验、显存占用估算全都要用到它。如果你还不清楚自己的cell尺寸是否合适,先回去算一下交换长度,这个我在第3节会详细展开。

几何那行setgeom(rect(512e-9, 256e-9))决定了磁性材料实际分布在哪些网格里。如果你跑出来的磁矩状态总是“多出一圈”或者“少了边上一行”,几何和网格一定有一个没对上。跑完第一次模拟后,我习惯先用save(m)存一次初态,直接看图确认几何区域正确,再开始正式计算。

材料参数里,Ms、Aex、alpha是最核心的三个,Ku1和anisU是各向异性项。对于没有特别易轴的薄膜样品,可以先把Ku1设成0,靠形状各向异性来稳定面内磁矩。

初始磁矩m = uniform(1, 0, 0.1)的意思是让每个元胞的磁矩方向都初始化为(1,0,0.1)然后归一化,制造一个微弱的面外扰动。这个扰动对于有些动力学过程是必要的,否则磁矩可能卡在完全对称的鞍点上。

输出设置里,tableadd记录的是随时间变化的标量或矢量,最终汇总到table.txt。autosave(m, 0.5e-12)是每隔0.5ns自动存一次磁矩空间分布。注意单位:这里是秒,所以0.5e-12就是0.5ps。模拟总时长run(1e-9)是1ns。

求解设置里我习惯加一行MaxDt := 1e-13,限制最大时间步长。Mumax3默认有自适应时间步,但有些参数组合下它容易放飞自我导致发散,手动限制之后就稳很多。

3. 材料参数逐一拆解:Ms、Aex、alpha、Ku1

3.1 饱和磁化强度Ms:所有磁场项的“底座”

饱和磁化强度指的是材料在饱和状态下单位体积的磁矩。它直接影响退磁场、外磁场力矩的大小,也影响铁磁共振频率。Ms在Mumax3里用A/m作单位,常见坡莫合金大约在8e5 A/m左右,钴铁硼在1.2e6 A/m左右,铁在1.7e6 A/m左右。

一个容易踩的坑是Mumax3内部有些量实际以T为单位存储,比如外加磁场Bext,但Ms的输入仍然用A/m。你如果非要把Ms填成以T为单位的数值,比如把800kA/m写成1.0,整个模拟的磁化动力学、开关场都会差一个数量级。这个单位换算关系是:磁极化强度J = μ0 × Ms,μ0约等于1.2566e-6,所以800kA/m大约对应1.006T。

Ms调大,退磁场也随之变大,这对薄膜器件的形状各向异性影响非常敏感。你在做参数优化时,如果发现矫顽力、磁畴结构对Ms特别敏感,先想想是不是退磁场效应主导了体系,而不仅仅是单个参数在起作用。

3.2 交换刚度Aex:和网格尺寸直接挂钩的参数

交换刚度Aex描述的是相邻磁矩之间的平行排列倾向,单位是J/m,它决定磁畴壁宽度、涡旋核心尺寸、斯格明子大小。坡莫合金的Aex通常在1.0e-11到1.5e-11 J/m量级,铁大概在2.1e-11 J/m左右。

Aex越大,磁矩越不容易剧烈变化,磁畴壁就越宽,涡旋核心也越大。做参数扫描时你会发现,Aex一改,很多“结构尺寸”都跟着变。它和网格尺寸有直接关系:如果你设的cell尺寸远大于交换长度,那交换作用在数值上根本分辨不出来,结果会粗得没法看。所以网格设计之前一定要用公式估算交换长度。

交换长度的公式是:

lex = sqrt(2 × Aex / (μ0 × Ms²))

以坡莫合金为例,Aex=1.3e-11,Ms=800e3,那么分母μ0×Ms²约等于1.2566e-6 × 6.4e11 = 8.04e5,分子2×1.3e-11就是2.6e-11,相除后大约是3.2e-17,开根号就是5.7e-9米,也就是5.7nm。这意味着你的cell至少要比5.7nm小很多,才有希望分辨涡旋核心或畴壁细节,实际使用中取2nm就很常见。如果只模拟大尺度的磁化翻转,cell粗糙一点也可以,但准静态特性会偏硬。

3.3 阻尼alpha:控制弛豫速度和结果形态

阻尼系数alpha是无量纲参数,描述磁矩向有效场弛豫的快慢。金属磁性材料通常在0.005到0.05之间,绝缘体磁性材料或某些特殊合金可以低到0.001甚至更低。alpha越小,磁矩就在进动轨道上来回绕得越久,弛豫到平衡态的时间就越长,你需要更长的模拟时间才能等到稳定结果。

alpha也是铁磁共振谱线宽度的来源。实验上通过FMR可以反推出alpha,而做动力学模拟时alpha会影响磁矩翻转路径和开关时间。例如模拟磁化翻转,alpha太小可能翻转时间拉长,出现明显的进动振荡;alpha太大虽然稳定得快,但可能掩盖一些真实的动力学行为。

做参数优化时我常把alpha当成一个“并行扫描变量”:它经常不直接影响稳态磁结构,但会影响到达稳态所需的时间和动态响应。比如跑涡旋弛豫,先开一个中等alpha快速弛豫,再换成小alpha做精确动力学,这样能省不少GPU时间。

3.4 各向异性Ku1与anisU:调矫顽力和易轴的钥匙

单轴各向异性由两个量控制:各向异性常数Ku1(单位J/m³)和各向异性轴方向anisU。它描述磁矩倾向沿某个特定方向排列。对垂直磁化薄膜,anisU通常设成(0,0,1),对应厚度方向易轴;对于面内易轴材料,改成(1,0,0)或(0,1,0)。

各向异性常数直接影响矫顽力。用Stoner-Wohlfarth模型做近似估计,单畴颗粒在零温下的各向异性场是Hk = 2 × Ku1 / (μ0 × Ms)。这个公式特别适合做参数优化的“数量级校准”:如果你的模拟开关场比这个估算值大或小得离谱,多半是模拟哪里出了问题。

一个常见误区是把各向异性和形状各向异性混在一起看。薄膜样品即使Ku1设成0,退磁场也会让面内比面外更有利,这就是形状各向异性。这时候如果你的目标是“模拟垂直记录介质”,就必须把Ku1调到足够大,否则磁矩不会被钉扎在垂直方向。

另外Mumax3还支持立方各向异性,对应的是磁场储能与晶轴的关系,需要的参数是Kc1、Kc2这些。基础模板里先用单轴各向异性就够了,等真正遇到立方材料(比如铁单晶)再扩展。

3.5 别忘了交换长度:一个公式帮你定网格

我已经在前面算过一遍交换长度,这里还要强调,它是网格设计的“第一约束条件”。交换长度太小的体系,如果网格不够细,就会出现局部磁矩翻转被数值抹平、涡旋核心失真、斯格明子消失这类假象。你调材料参数调了半天,其实问题出在网格精度上。

实际模拟中,cell尺寸一般取交换长度的三分之一到二分之一比较稳妥。比如交换长度5.7nm,cell取2nm左右。若cell取得比交换长度还大,交换作用项基本失效,磁畴壁会人为变窄,这会让你的参数优化结果彻底失真。

除了交换长度,还要看一眼磁畴壁宽度,大概可以用π×sqrt(Aex/Ku1)来估计。如果你调大Ku1导致畴壁变窄,原本足够的网格可能又不够了,必须回头重新检查cell尺寸。这就是为什么我建议把“网格校验”写进每一轮参数优化的检查清单,而不是只做一次。

4. 参数优化三步走:手动、批量、自动

4.1 先定目标:拿开关场当优化指标

参数优化前,必须先有一个明确的量化指标。如果只是想“看看磁矩长什么样”,那不叫优化,叫探索。真正优化时,要有目标函数,比如尽量降低矫顽力、提高热稳定性、缩短翻转时间、获得特定尺寸的磁畴或者涡旋。

我第二个常用例子是纳米点阵列的开关场优化。开关场(也叫翻转场)就是从饱和态沿相反方向加磁场,磁矩发生不可逆翻转的最小外场。这个量既受Ms、Aex影响,也受各向异性Ku1影响,很适合用来演示参数扫描流程。

具体操作上,可以在一个脚本里分阶段改变外场,每次跑一段足够长的弛豫时间,再记录此时磁矩的平均分量。比如初始沿+x饱和到100mT,然后逐段降到0、再到反方向,观察平均磁化Mx什么时候发生符号翻转。

4.2 批量扫描参数:用Python脚本一次跑几十组

Mumax3本身没有内置优化器,但它的脚本语法特别适合外部批量生成。我自己常用的做法是,把mx3模板里的关键参数用占位符标记,然后用Python循环生成多个输入文件,在每个子目录里调用mumax3运行。下面是一个扫描Ms的示例脚本:

import os import subprocess cases = [ ("Ms_600k", 600e3), ("Ms_700k", 700e3), ("Ms_800k", 800e3), ("Ms_900k", 900e3), ("Ms_1000k", 1000e3), ] with open("template.mx3", "r") as f: template = f.read() for name, ms in cases: os.makedirs(name, exist_ok=True) content = template.replace("MS_PLACEHOLDER", f"{ms:.1e}") with open(os.path.join(name, "input.mx3"), "w") as f: f.write(content) print(f"running {name} ...") subprocess.run(["mumax3", "input.mx3"], cwd=name)

这里的技巧是模板里写Ms := MS_PLACEHOLDER,运行时用Python替换成具体数值。每个case各自建一个子目录,输出文件互不覆盖,之后整理数据也方便。如果你要扫描多个参数,比如Ms和alpha的组合,就往cases列表里多放几组,一跑就是一个二维参数网格。

批量跑的时候注意GPU资源。单卡上同时跑多个mumax3进程不一定快,因为显存和流处理器会被抢。我一般是串行跑,或者按显存大小同时跑两到三个,具体看卡的性能和模型规模。

4.3 提取结果:从table.txt里自动算指标

Mumax3跑完后,每个子目录里会生成table.txt,记录时间、外场、平均磁化、总能量等信息。我写参数优化脚本时,会专门写一个“结果提取”函数,把每个参数组合对应的指标取出来,汇总成一张表。

import pandas as pd import glob rows = [] for name, _ in cases: path = os.path.join(name, "table.txt") df = pd.read_csv(path, sep="\t") # 打印列名,实际列名以你 tableadd 顺序为准 print(name, df.columns.tolist()) # 取最后一行的平均磁化 x 分量 last = df.iloc[-1] rows.append({"name": name, "mx_final": last["m_0"]}) result = pd.DataFrame(rows) print(result)

要注意Mumax3输出的“m”是归一化磁矩,而不是以A/m为单位的实际磁化强度。列名的具体写法可能因版本略有差异,可能是m_0、m_1、m_2,也可能是m_x、m_y、m_z,所以先打印df.columns看一眼最保险。

拿到最后一行的平均磁化分量之后,我就能画出“扫描参数–响应指标”的曲线。比如扫Ku1时,可以把每个Ku1对应的开关场整理出来,和Stoner-Wohlfarth估算的Hk曲线放在一起比对,检查数值模拟是否符合物理预期。这一步非常能暴露脚本里的隐藏错误。

4.4 更进一步:把优化写成自动化循环

手动扫描虽然直观,但参数多了就很累。如果你已经有一个明确的目标函数,比如让模拟磁滞回线和实验曲线尽量接近,那完全可以把Mumax3的模拟流程包装成一个子函数,交给数值优化库去自动迭代。

from scipy.optimize import minimize def simulate(params): ms, ku = params[0], params[1] # 生成脚本、运行、读取结果,返回一个标量误差 return error res = minimize(simulate, [800e3, 1e4], method="Nelder-Mead") print(res.x)

每次迭代都会启动一次新的Mumax3计算,所以这个方案对单次模拟时间非常敏感。我建议前面先用较粗的网格和较短的模拟时间做粗优化,等找到大致最优区域后,再拿到细网格上复算。不然一次模拟一分钟,几百次迭代就是大半天。

另外一个更省事的思路:如果参数空间本身就是两三个变量,直接生成一个规整的网格扫描,然后可视化结果热力图,很多时候一眼就能看出最优区在哪。比如横轴Ms、纵轴Ku1、颜色代表开关场,这种“扫描热图”比数字表格直观得多。

5. 我踩过的坑:常见报错和排查方法

5.1 NaN、发散、跑一半崩了

NaN问题基本是所有微磁学初学者的噩梦。我遇到的最常见原因是最大时间步长放太宽,导致数值不稳定;其次就是初始磁矩设置得太极端,比如直接让相邻元胞反向排列,交换场巨大,一开跑直接爆掉。

解决办法也比较简单。第一,给MaxDt设一个比较保守的值,比如MaxDt := 1e-13,先跑通再逐步放大。第二,初始磁矩尽量用平缓的状态,比如uniform(1,0,0),不要一开始就弄出尖锐的磁畴壁。第三,如果用了温度模块或者随机场,记得检查随机种子和热涨落幅度,有限温度下出现意外翻转不代表发散,要区分清楚物理涨落和数值爆掉。

另一个隐蔽原因是把Bext填得过大,比如填了10T以上,磁矩进动频率极高,自适应时间步也扛不住。做磁场扫描时注意磁场范围和MaxDt的匹配关系。

5.2 显存不足:先少算一点再慢慢加

显存不足在网格稍大的模型里太常见了。Mumax3在GPU上要同时存磁矩、有效场、交换场、退磁场辅助场等多个三维数组,单精度下每个量都不小。比如256×128×32的网格,光三维场就几十MB,叠加多个中间变量、再考虑CUDA的临时缓存,显存很容易吃满。

我的经验是先跑一个最小的网格验证流程正确,再逐步放大。比如先Nx=64、Ny=64、Nz=1跑通,然后放大到256×128、Nz=4,最后再上真正的大模型。不要一上来就把Nz设成32,炸了还不好定位问题。

如果确实需要大网格,可以考虑缩小cell尺寸返回来减少网格数,或者切分模拟区域分步计算。Mumax3的优势是GPU加速,但GPU显存是硬上限,学会“用小模型调参数、用大模型出结果”是省时间的重要技巧。

5.3 结果和实验差很多?先检查这四处

参数优化最让人崩溃的,不是跑不出来,而是跑出来和实验对不上。我一般先按这个顺序排查:

一是网格密度是否满足交换长度约束。如果cell尺寸大于交换长度,模拟会人为“变硬”,畴壁变窄、开关场偏高。

二是弛豫时间是否足够。有时候磁矩还在慢悠悠地转,你就认为它达到稳态了,提取的指标自然不对。看table.txt里的磁矩曲线,尾部必须是平的才算稳定。

三是温度因素。Mumax3默认是0K模拟,没有热涨落,所以零温矫顽力通常会比室温实验值偏高。如果你拿模拟结果直接和室温实验比,关不上门很正常。可以开有限温度模拟,但有限温度下结果有随机性,需要多跑几次取平均。

四是几何边缘和实际样品的差异。矩形阶梯近似会让边缘出现非物理钉扎,尤其尺寸很小的纳米结构。这种情况下可以加密网格,或者用更接近实验的真实形状文件导入几何。Mumax3支持从图片读取几何文件,你可以用一张带抗锯齿的掩模图来定义样品形状,效果会好很多。

5.4 常见问题速查表

现象大概率原因排查方向
NaN或计算发散时间步过大、初始磁矩太尖锐、外场过大降低MaxDt,改用平缓初态,检查Bext量级
GPU显存不足三维网格过大先降低Nz或整体网格,再逐级放大
翻转场偏大0K模拟、网格太粗、未弛豫充分检查交换长度,延长run时间,开温度模拟
能量曲线不平滑几何与网格不匹配、磁矩有钉扎保存初态图,检查setgeom区域
表格里列名对不上不同版本的Mumax3输出命名有差异先print columns,再取对应列

这张表是我每次给新模型排错时都会过一遍的清单。优先处理网格和单位,其次才怀疑物理参数。

6. 一点个人经验:参数优化前先让模型“正常”

最后分享两个我认为最值得记住的教训。

第一个教训是,别在模型还没跑稳的时候就开始大规模调参数。我见过不少人拿着一个会偶尔出NaN的脚本去跑几百组扫描,最后数据一堆,能用的没几条。正常的操作顺序永远是:先用小网格、短时间把单次模拟跑通跑稳,确认磁矩演化行为符合物理直觉,再扩大参数扫描范围。哪怕第一次只能跑一个小尺寸模型,也好过跑出一个全是假象的大模型。

第二个教训是,参数优化不是“把文献参数抄一遍”。文献给的Ms、Aex、alpha通常来自特定厚度、特定衬底、特定制备工艺的样品,和你自己模拟的几何条件很可能不匹配。真正靠谱的做法是,先用文献值做初始点,然后围绕目标指标做小范围扫描,找到符合自己体系的最优值。扫描结果如果和解析估算偏差很大,先怀疑脚本和网格,而不是马上怀疑物理模型。

顺手再分享一个小技巧:做完一批参数扫描后,我会把所有table.txt合并成一个大表,用Python画几条关键的响应曲线,保存成一张图存在工作目录里。这样三个月后回来看项目,不用重新跑模拟,一眼就能想起当时的数据规律。这个习惯帮我省了大量重复劳动。

Mumax3的门槛其实不在软件本身,而在你能不能把单位、网格、物理参数这三件事串起来。只要基础设置扎实,参数优化就是一次有章法的系统扫描,而不是靠感觉盲调。希望这套模板和排查思路能帮你少走点弯路。

返回列表