你有没有尝试过在模型中加入一个随机创建的几何对象?比如你想要模拟一种天然材料,或者一种在尺寸变化上具有某些已知的统计分布的零件排列。当遇到这类情况时,你可能希望在 COMSOL Multiphysics® 软件中创建一个随机几何对象。对此,我们可以借助模型方法来实现这个需求。本文我们将以一块美味的奶酪为例,介绍具体的操作方法。建立瑞士奶酪模型
评选出世界上最好的奶酪是一项颇具争议的任务,但是我会毫无犹豫地发表我的观点:优质的埃曼塔奶酪(Emmentaler cheese)绝对可以胜出。一位奶酪制作大师可能会开玩笑说,真正增添风味是奶酪上的蜂窝状圆孔,因此如果要在 COMSOL Multiphysics 中建立一个逼真的圆盘状奶酪模型,我们必须加上这些小孔。埃曼塔奶酪的模型,小孔的位置与大小均为随机设定。
事实证明,瑞士奶酪中的小孔形成的原因相当复杂,所以我们不会去模拟小孔的形成,而是简单地建立一个如上图所示的奶酪模型。我们计划在奶酪中添加一组随机分布的小孔,其半径在上限值和下限值之间随机浮动。在 COMSOL Multiphysics 中,我们可以借助模型方法功能创建这个随机几何对象。接下来让我们看看如何实现……在 COMSOL Multiphysics® 中引入模型方法
在 Windows® 平台上运行 COMSOL Multiphysics 并使用模型开发器时,功能区将显示开发工具选项卡,如下图所示。其中一个选项是录制方法。单击此选项后,会提示您输入新方法的名称和方法类型。您可以输入任意符合要求的字符串来定义方法名称,方法类型可以选择 App 方法或模型方法。App 方法适用于 COMSOL App,这个教学视频介绍了它的使用过程。模型方法适用于 COMSOL Multiphysics 的底层模型,并且可以处理(或添加信息到)现有的模型数据。开发工具选项卡,显示了录制方法和运行模型方法按钮。
单击录制方法对话框中的确定按钮后,你会看到高亮显示的红色线框环绕整个图形用户界面。随后所有的执行操作都会录制到此方法中,直到单击停止录制按钮。你可以切换到 App 开发器来查看录制完的方法。下图显示了录制完单个几何对象的创建过程的 App 开发器和方法。这是一个标签为 cyl1、半径为 40 cm、高度为 20cm 的圆柱体,对于圆盘奶酪而言,这是一个良好的初始近似值。App 开发器显示了用于建立几何对象的模型方法代码。
在模型开发器中,借助开发工具选项卡下的运行模型方法按钮,我们能够在其他任何模型文件(只要模型文件的几何序列中不存在含 cyl1 标签的现有对象)中调用这个模型方法。当然,这个简单的模型方法仅创建了一个圆柱体。如果要模拟小孔,我们需要在方法中引入一些随机性。下文我们将研究这一点。创建随机的几何特征集
在模型方法中,我们可以调用包含 Math.random类在内的标准 Java® 类,这种类会返回大于或等于 0.0 且小于 1.0 的双精度数。我们将使用这种类,加上新编写的少量代码,在圆盘奶酪模型中建立指定数量的位置和大小随机设定的小孔。假设整块奶酪中随机分布 1000 个小孔,每个小孔的半径在 0.1cm 到 1cm 之间随机分布。请不要忘记,埃曼塔奶酪有一层天然的坚硬外皮,其上不会形成小孔。所以,我们需要添加一些逻辑,确保 1000 个小孔实际存在于奶酪内部。下方的完整模型方法(添加了行号,并将文本字符串标记为红色)展示了具体步骤。
1 int NUMBER_OF_HOLES = 1000;
2 int ind = 0;
3 double hx, hy, hz, hr = 0.0;
4 double CHEESE_HEIGHT = 20.0;
5 double CHEESE_RADIUS = 40.0;
6 double RIND_THICKNESS = 0.2;
7 double HOLE_MIN_RADIUS = 0.1;
8 double HOLE_MAX_RADIUS = 1.0;
9 model.component("comp1").geom("geom1").lengthUnit("cm");
10 model.component("comp1").geom("geom1").selection().create("csel1", "CumulativeSelection");
11 while (ind < NUMBER_OF_HOLES) {
12 hx = (2.0*Math.random()-1.0)*CHEESE_RADIUS;
13 hy = (2.0*Math.random()-1.0)*CHEESE_RADIUS;
14 hz = Math.random()*CHEESE_HEIGHT;
15 hr = Math.random()*(HOLE_MAX_RADIUS-HOLE_MIN_RADIUS)+HOLE_MIN_RADIUS;
16 if ((Math.sqrt(hx*hx+hy*hy)+hr) > CHEESE_RADIUS-RIND_THICKNESS) {continue; }
17 if (((hz-hr) < RIND_THICKNESS) || ((hz+hr) > CHEESE_HEIGHT-RIND_THICKNESS)) {continue; }
18 model.component("comp1").geom("geom1").create("sph"+ind, "Sphere");
19 model.component("comp1").geom("geom1").feature("sph"+ind).set("r", hr);
20 model.component("comp1").geom("geom1").feature("sph"+ind).set("pos", new double[]{hx, hy, hz});
21 model.component("comp1").geom("geom1").feature("sph"+ind).set("contributeto", "csel1");
22 ind++;
23 }
24 model.component("comp1").geom("geom1").create("cyl1", "Cylinder");
25 model.component("comp1").geom("geom1").feature("cyl1").set("r", CHEESE_RADIUS);
26 model.component("comp1").geom("geom1").feature("cyl1").set("h", CHEESE_HEIGHT);
27 model.component("comp1").geom("geom1").create("dif1", "Difference");
28 model.component("comp1").geom("geom1").feature("dif1").selection("input").set("cyl1");
29 model.component("comp1").geom("geom1").feature("dif1").selection("input2").named("csel1");
30 model.component("comp1").geom("geom1").run();
1. 初始化并定义奶酪内的小孔总数。
2. 初始化并定义用于后续步骤的索引计数器。
3. 初始化一组用于保留每个小孔的 xyz 位置和半径的双精度数。
4–8. 初始化并定义一组数字,以 cm 为单位定义奶酪的高度、半径、环绕线粗细以及小孔的最大和最小半径。
9. 将几何的长度单位设置为 cm。
10. 创建一个新选择集,并添加标签 csel 和名称 CumulativeSelection。请注意:如果类似的选择集已存在,此时该方法将失败。如果您要在同一个文件中反复运行该方法,可以通过修改方法来解决这个问题。
11. 初始化 while 循环,创建指定数量的孔。
12–14. 通过调用随机方法和缩放输出来定义小孔的 xyz 坐标,使小孔的 xyz 坐标位于奶酪模型的笛卡尔坐标的外部界限之内。
15. 在规定的限值范围内定义小孔半径。
16–17. 检查小孔的位置和尺寸是否会使其脱离奶酪。如果是,继续执行 while 循环的下一次迭代,停止执行循环中的剩余代码。此检查可在一行中进行,也可以分为三行,这取决于您的编程风格。
18. 创建一个球体,使其名称基于当前的索引值。
19–20. 指定新创建球体的半径和位置。虽然半径可以通过一个双精度数直接传递,但位置必须使用双精度数组。
21. 指定此球体特征属于名为 csel1 的选择集的一部分(做出了贡献)。
22–23. 对索引运行迭代,表明已创建球体,并结束 while 循环。
24–26. 创建一个代表圆盘奶酪的圆柱体。
27–29. 建立一个布尔差集运算。要添加的对象是圆柱体,要减去的对象是所有球体的选择。
30. 运行整个几何序列,将所有球体从圆柱体中切除,最终形成圆盘奶酪。我们可以在新的(或空的)模型文件中运行这个方法,从而创建一个圆盘奶酪模型。每一次重新运行此方法,都会得到一个不同的模型。模型文件中的几何序列包含全部球体、圆柱体以及布尔运算。如果有必要,我们还可以在模型方法中添加一些额外的代码,直接输出最终模型(奶酪)的几何文件。可以使用 COMSOL Multiphysics 格式或者 STL 文件格式编写模型文件,也可以使用任何包含 Parasolid® 软件内核的可选模块,并以 Parasolid® 软件或 ACIS® 软件文件格式导出。相比于直接处理完整的几何序列,在处理最终几何之前先进行导出和重新导入操作的效率更高。将被吃掉的埃曼塔圆盘奶酪的模型。
结语
文中,我们通过一个简单示例介绍了如何使用模型方法来创建位置和大小随机分布的几何对象。我们留下了一些尚未解决的问题,例如,如何确保小孔不重叠,或者如何模拟密集堆积的布局等。这些问题本质上都是各自领域中的一些数学难题。当然,模型方法还有许多其他用途,我们会在另一篇文章中详述。也可以通过其他方法创建随机几何对象,例如定义参数化表面。如需了解文中提到的案例详情,请点击底部“阅读原文”查看。如果您有相关问题,或者文中介绍的内容没有涉及您所关注的问题,欢迎留言讨论。