使用 Excel® 和 Visual Basic® 构建 COMSOL Multiphysics® 模型

2017年 3月 15日

您有没有想过在 COMSOL Multiphysics® 软件中自定义或构建基于 Excel® 电子表格数据的模型?Excel 电子表格在许多科学和工程应用程序中被用来呈现、协作和存储数据。使用 Microsoft® Visual Basic® for Applications(VBA) 和 LiveLink™ for Excel®(COMSOL 的接口产品),我们可以在 Excel® 电子表格软件中构建和控制模型设置和参数。这篇博文,我们将介绍如何实现这个过程并列举了一些例子。

将 LiveLink™ for Excel®与 VBA 结合使用

LiveLink™ for  Excel® 是一款接口产品,可以让我们将 Excel 数据连接到 COMSOL Multiphysics 仿真中。如果您是
LiveLink™ for Excel®的新用户,您可以阅读以下文档(安装软件后访问)开始使用:

  • LiveLink™ for Excel® 简介
  • LiveLink™ for Excel® 用户指南

Excel® 电子表格软件还提供了在 Excel 工作簿中定义和运行 VBA 的功能。虽然我们可以手动编写 VBA 脚本,但也可以使用 COMSOL Multiphysics 用户界面从现有模型中生成它们。正如我们将在一些示例的帮助下看到的那样,通过 LiveLink™ for Excel®实现 VBA 的使用是很容易的。我们将研究一个常见的应用程序来检索和更新 COMSOL Multiphysics 模型中的参数。

尽管这个功能很有用,但 VBA 和 LiveLink™ for Excel® 还有更多的用途。例如,我们将了解如何构建 COMSOL Multiphysics 模型并使用 Excel 工作簿中插入的一些基本形状定义模型几何。

注意:此处讨论的示例使用 Excel® 2010 版显示,但其他版本中的过程相同。

使用 VBA,可以连接组件对象模型 (Component Object Model ,COM) 组件。当您安装LiveLink™ for Excel® 后,还会安装一个 COM 接口组件,可用于与 COMSOL Multiphysics® 连接。COMSOL Multiphysics Server 和 COMSOL Multiphysics 模型之间接口的两个基本 COM 对象是:

comsolcom.comsolutil
comsolcom.modelutil

通过使用 comsolcom.comsolutil,可以启动 COMSOL Multiphysics Server、连接和断开与服务器的连接。使用 comsolcom.modelutil,我们可以连接 COMSOL Multiphysics 模型。

使用 VBA 编辑器

借助随 Excel® 电子表格软件安装的编辑器,我们可以在 Excel 工作簿中编写和编辑 VBA 脚本。可以通过几种不同的方式访问编辑器窗口。例如,如果我们右键单击 Excel 工作表选项卡并选择 View Code,则会显示编辑器。如果我们创建或编辑宏,也会显示编辑器。还可以在 Excel® 电子表格软件的工具栏中启用“开发人员” 选项卡,其中包含用于访问编辑器和其他开发相关功能的按钮。

Screenshot of a sheet in Excel.

在 VBA 中访问 COM 组件

我们可以使用下面的声明在 VBA 中创建 comsolcom.comsolutil comsolcom.modelutil 对象的动态实例。

设置 comsolutil = CreateObject("comsolcom.comsolutil")
设置 modelutil=CreateObject("comsolcom.modelutil")

Screenshot showing how to access COM components in VBA.

这个声明的优点是版本独立。最新安装的版本 comsolcom.comsolutil,和 comsolcom.modelutil 在运行时使用。

也可以使用下面含静态 COM 引用的声明 comsolcom.comsolutil comsolcom.modelutil

Dim comsolutil As comsolutil
Set comsolutil = CreateObject("comsolcom.comsolutil")
Dim modelutil As modelutil
Set modelutil = CreateObject("comsolcom.modelutil")

Screenshot showing an alternate way of accessing COM components in VBA.

使用此声明的一个优点是,在使用定义的类型时,可以在 VBA 中获得帮助。

Screenshot showing the help options in VBA for defined types.

为了能够为 comsolutilmodelutil 定义静态类型,我们必须向 ComsolCom 添加一个 COM. 我们可以通过在 Excel® 电子表格软件中打开 VBA 编辑器,选择 Tools 菜单,选择 References,然后为已安装的版本选择 ComsolCom 来实现。

Screenshot demonstrating how to add a COM reference.

启动 COMSOL Multiphysics 服务器,使用 VBA 连接和断开连接

以下简短的 VBA 脚本说明了如何启动 COMSOL Multiphysics Server,连接到已启动的服务器,以及断开与服务器的连接。行调用comsolutil.TimeOutHandle(True)应用超时处理程序,该处理程序将等待长时间运行的命令返回给Excel。

Set comsolutil = CreateObject("comsolcom.comsolutil")
Set modelutil = CreateObject("comsolcom.modelutil")
调用 comsolutil.TimeOuthandler(True)
调用 comsolutil.StartComsolServer(True)
调用 modelutil.connect
调用 modelutil.Disconnect

Screenshot of Visual Basic showing how to start a COMSOL Multiphysics Server.

从 COMSOL API 迁移使用 Java® 和应用程序方法

如果你有将 COMSOL API 用于 Java® 或在应用程序方法中编写代码的经验,那么你应该了解一下语法差异。例如,在检索模型特征列表时,模型中的研究语法类似。因此,为了检索模型中的研究,以下语法有效:

model.study()

但是,在访问特定研究时,语法是不同的。例如,当 std1 使用 COMSOL API 检索带有研究标签 std,以与 Java® 或应用程序中的代码一起使用时,语法 model.study("std1") 有效。但是,对于 VBA® 和 LiveLink™ for Excel®,必须改用以下语法:

COMSOL Multiphysics® 模型中的接口参数

VBA 和 LiveLink™ for Excel® 中的一个常见应用是检索和更新 COMSOL Multiphysics® 模型中的参数。下面,我们将看到这是多么容易实现。

下图中的 VBA 脚本启动了 COMSOL Multiphysics 服务器,连接到启动的服务器,从与Excel® 工作簿相同的目录中加载母线板焦耳热(使用 LiveLink™ for Excel®)模型,使用更新的长度参数求解模型, 并用另一个文件名保存更新的模型。

以下 VBA 脚本提取模型中参数的参数数据并将其插入 Excel 工作簿中。

如何使用 Excel® 和 Visual Basic® 构建 COMSOL Multiphysics® 模型

在接下来的一个示例中,我们将创建一个 COMSOL Multiphysics 模型并使用 固体传热 接口求解一个二维模拟。这个过程包括在 Excel® 中通过添加带有一些说明的文本框、外部温度边界、内部温度边界和用于求解模拟的按钮来定义几何。模型求解后,结果图会插入 Excel® 工作簿中。下面给,我们来详细介绍一下这些步骤。

1:首先,创建一个带有说明文本的文本框并将其插入到 Excel 工作簿中。

Inserting a text box into an Excel workbook.

2:然后,为模拟定义一个区域。我们选择一个自由形状并将其插入 Excel® 工作簿中。然后,选择 SimulationRegion 作为形状的名称。通过右键单击形状并选择 Edit Polygon 使多边形可编辑。然后编辑形状,如下所示。

Editing a polygon in an Excel workbook.

3:创建了一个温度更高的内部边界。为此,我们使用椭圆形状,创建一个圆形,并将其插入自由形状中。选择 HeatSource 作为形状的名称。椭圆形状必须位于 Simulation Region 形状内。

Creating an inner boundary in the polygon in the Excel workbook.

4;然后添加一个带有文本 Solve 的文本框形状以用作按钮。右键单击该按钮,选择 Assign Macro,然后创建一个名为 Solve_Click 的新宏。

5:接下来,我们在 VBA® 编辑器中打开指定的宏并用以下脚本替换内容:

Option Explicit
 
Sub Solve_Click()
 
Dim node
Dim coordinates
Dim index
Dim newPolygonTable() As Double
Dim newHeatSource(1 To 2) As Double
Dim model As ModelImpl
 
newHeatSource(1) = Sheets("Sheet1").Shapes("HeatSource").DrawingObject.Left + (Sheets("Sheet1").Shapes("HeatSource").DrawingObject.Width / 2)
newHeatSource(2) = Sheets("Sheet1").Application.Height - (Sheets("Sheet1").Shapes("HeatSource").DrawingObject.Top + (Sheets("Sheet1").Shapes("HeatSource").DrawingObject.Height / 2))
 
Dim nNodes As Long
nNodes = Sheets("Sheet1").Shapes("SimulationRegion").Nodes.Count
ReDim Preserve newPolygonTable(1 To nNodes, 1 To 2)
 
For Each node In Sheets("Sheet1").Shapes("SimulationRegion").Nodes
    coordinates = node.points
    index = index + 1
    newPolygonTable(index, 1) = coordinates(1, 1)
    newPolygonTable(index, 2) = Sheets("Sheet1").Application.Height - coordinates(1, 2)
Next
 
Set model = SetModel(newPolygonTable, newHeatSource)
 
Call model.get_study("std1").Run
 
If Not ContainsTag(model.result().tags(), "pg1") Then
    Call model.result().Create("pg1", "PlotGroup2D")
   Call model.get_result("pg1").feature().Create("surf1", "Surface")
    Call model.get_result("pg1").Label("Temperature (ht)")
    Call model.get_result("pg1").set("data", "dset1")
   Call model.get_result("pg1").get_feature("surf1").Label("Surface")
    Call model.get_result("pg1").get_feature("surf1").set("colortable", "ThermalLight")
    Call model.get_result("pg1").get_feature("surf1").set("data", "parent")
    Call model.get_result("pg1").get_feature("surf1").Run
End If
Call model.get_result("pg1").Run
 
Call Range("J10").Select
Dim tempPng As String
tempPng = Environ("Temp") & "\PolygonHeat" & Format(Now(), "yyyymmddhhmmss") & ".png"
 
Dim exportTag As String
exportTag = model.result().Export.uniquetag("export")
Call model.result().Export().Create(exportTag, "Image2D")
Call model.result().get_export(exportTag).set("plotgroup", "pg1")
Call model.result().get_export(exportTag).set("pngfilename", tempPng)
Call model.result().get_export(exportTag).Run
 
If Dir(tempPng)  "" Then
   Call Application.ActiveSheet.Pictures.Insert(tempPng)
    SetAttr tempPng, vbNormal
    Kill tempPng
End If
 
Call model.result().Export().Remove(exportTag)
 
End Sub
 
Private Function SetModel(ByRef newPolygonTable() As Double, ByRef newHeatSource() As Double) As Variant
 
Dim comsolutil As comsolutil
Set comsolutil = CreateObject("comsolcom.comsolutil")
Dim modelutil As modelutil
Set modelutil = CreateObject("comsolcom.modelutil")
Dim model As ModelImpl
 
If Not IsConnected(modelutil) Then
    Call ConnectServer(comsolutil, modelutil)
End If
 
If Not ContainsTag(modelutil.tags(), "PolygonHeatModel") Then
    Set SetModel = CreateModel(modelutil, "PolygonHeatModel", newPolygonTable, newHeatSource)
    Exit Function
End If
 
Set model = modelutil.model("PolygonHeatModel")
Call model.get_geom("geom1").get_feature("pol1").set("table", newPolygonTable)
 
Call model.get_geom("geom1").get_feature("c1").set("x", newHeatSource(1))
Call model.get_geom("geom1").get_feature("c1").set("y", newHeatSource(2))
Call model.get_geom("geom1").runAll
 
Set SetModel = model
 
End Function
 
Private Function CreateModel(ByRef modelutil As modelutil, ByRef modelTag As String, ByRef newPolygonTable() As Double, ByRef newHeatSource() As Double) As Variant
Dim model As ModelImpl
Set model = modelutil.Create(modelTag)
 
Call model.ModelNode().Create("comp1")
 
Call model.geom().Create("geom1", 2)
Call model.mesh().Create("mesh1", "geom1")
 
Call model.get_geom("geom1").Create("pol1", "Polygon")
Call model.get_geom("geom1").get_feature("pol1").set("source", "table")
Call model.get_geom("geom1").get_feature("pol1").set("table", newPolygonTable)
Call model.get_geom("geom1").Selection().Create("csel1", "CumulativeSelection")
Call model.get_geom("geom1").get_feature("pol1").set("contributeto", "csel1")
Call model.get_geom("geom1").get_run("pol1")
 
Call model.get_geom("geom1").Create("c1", "Circle")
Call model.get_geom("geom1").get_feature("c1").set("r", 0.01)
Call model.get_geom("geom1").get_feature("c1").set("x", newHeatSource(1))
Call model.get_geom("geom1").get_feature("c1").set("y", newHeatSource(2))
Call model.get_geom("geom1").Selection().Create("csel2", "CumulativeSelection")
Call model.get_geom("geom1").get_feature("c1").set("contributeto", "csel2")
 
Call model.get_geom("geom1").Run
Call model.get_geom("geom1").get_run("fin")
 
Call model.Material().Create("mat1", "Common", "comp1")
Call model.get_material("mat1").set("family", "copper")
Call model.get_material("mat1").get_propertyGroup("def").set("heatcapacity", "385[J/(kg*K)]")
Call model.get_material("mat1").get_propertyGroup("def").set("density", "8960[kg/m^3]")
Call model.get_material("mat1").get_propertyGroup("def").set("thermalconductivity", "400[W/(m*K)]")
 
Call model.Physics().Create("ht", "HeatTransfer", "geom1")
Call model.get_physics("ht").Create("temp1", "TemperatureBoundary", 1)
Call model.get_physics("ht").Create("temp2", "TemperatureBoundary", 1)
Call model.get_physics("ht").get_feature("temp2").set("T0", "293.15[K]+20")
Call model.get_physics("ht").get_feature("temp1").Selection().named("geom1_csel1_bnd")
Call model.get_physics("ht").get_feature("temp2").Selection().named("geom1_csel2_bnd")
 
Call model.study().Create("std1")
Call model.get_study("std1").Create("stat", "Stationary")
Call model.get_study("std1").Run
 
Call model.result().Create("pg1", "PlotGroup2D")
Call model.get_result("pg1").Label("Temperature (ht)")
Call model.get_result("pg1").set("data", "dset1")
Call model.get_result("pg1").feature().Create("surf1", "Surface")
Call model.get_result("pg1").get_feature("surf1").Label("Surface")
Call model.get_result("pg1").get_feature("surf1").set("colortable", "ThermalLight")
Call model.get_result("pg1").get_feature("surf1").set("data", "parent")
 
Set CreateModel = model
 
End Function
 
Private Function IsConnected(modelutil As modelutil) As Boolean
 
'Try to access model tags. If not connected to a server this will throw an error.
On Error GoTo ErrorHandler
Call modelutil.tags
IsConnected = True
Exit Function
 
ErrorHandler:
IsConnected = False
 
End Function
 
Private Function ConnectServer(comsolutil As comsolutil, modelutil As modelutil)
 
On Error GoTo ErrorHandler
Call modelutil.connect
If Not comsolutil.isGraphicsServer() Then
    MsgBox prompt:="The running COMSOL Multiphysics Server is not a graphics server. Exporting results will not work.", Buttons:=vbOKOnly, Title:="COMSOL"
End If
Exit Function
 
ErrorHandler:
 
Call comsolutil.TimeOuthandler(True)
Call comsolutil.StartComsolServer(True)
Call modelutil.connect
 
End Function
 
Private Function ContainsTag(tags() As String, tag As String) As Boolean
 
ContainsTag = False
If (UBound(Filter(tags, tag)) > -1) Then
    ContainsTag = True
End If
 
End Function

6:输入代码后,点击 Solve 按钮。这将执行宏中定义的 VBA 脚本并根据 Excel 工作簿中的形状创建模型。模型求解后,图形被插入到工作表中。

A COMSOL Multiphysics model is inserted into an Excel worksheet.

如果更改 Simulation Region 形状并将 Heat Source 形状移动到 Simulation Region 内的另一个位置,则模型和结果将不同。

很容易想象我们如何根据 Excel 工作簿中的其他形状、图表和数据来控制和编辑此模型。还可以从 COMSOL Multiphysics 模型中提取数值结果并生成 Excel 工作簿内容,例如在报告中使用。

这篇博文只是介绍了可以使用 VBA 和 Excel®执行的操作的一些皮毛。作为用户,你可以访问整个 COMSOL API,从而可以访问所有模型设置和参数。这样,你就可以定义任何类型的模型并在使用 COMSOL Multiphysics 求解后提取其数据。

Microsoft、Excel 和 Visual Basic 是 Microsoft Corporation 在美国和/或其他国家/地区的注册商标或商标。

Oracle 和 Java 是 Oracle 和/或其附属公司的注册商标。

博客分类


评论 (0)

正在加载...
浏览 COMSOL 博客