Gmsh 示例 t4.py 无法找到 t4_image.png,其他示例正常运行

0 投票
1 回答
55 浏览
提问于 2025-04-14 18:02

我的目标是自己解决之前的问题,链接在这里:如何从我的多边形几何图形生成网格,以便进行几何优化的有限元分析?,我打算使用Gmsh来实现。

我在macOS 10.15.7的Intel Core i5上,通过pip安装了Gmsh也可以在这里找到)版本4.12.2,使用的是Anaconda的Python 3.7。

我运行了前五个示例t1到t5.py,结果都很好,除了t4。

你可以在这里查看t4的文档:https://gmsh.info/dev/doc/texinfo/gmsh.html#t4

我遇到的情况是:

Exception: Could not open file `/Users/davido/Documents/Gmsn/../t4_image.png'

注意:有个朋友在Windows上用Python 3.11.5运行t4.py,结果很好。不过我现在没有办法换电脑或操作系统,也不想为了“看看会发生什么”而升级我的Anaconda。

我在问题的底部添加了t4.py的内容,它使用了一些我不太熟悉的路径规范(我更擅长数值计算),我不知道/../是什么意思。

我在电脑上找不到任何t4_image.png的实例,除了几周前在安装Gmsh时Anaconda包里有一个。

因为在网格中打孔正是我需要做的事情,以回答之前提到的问题,所以我希望能让这个示例正常工作。

错误信息:

(base) davido@Davidos-MacBook-Air Gmsn % python -i t4.py
Info    : Meshing 1D...
Info    : [  0%] Meshing curve 1 (Line)
Info    : [ 10%] Meshing curve 2 (Line)
[lines removed]
Info    : [ 90%] Meshing curve 19 (Circle)
Info    : [100%] Meshing curve 20 (Line)
Info    : Done meshing 1D (Wall 0.00703093s, CPU 0.024232s)
Info    : Meshing 2D...
Info    : [  0%] Meshing surface 22 (Plane, Frontal-Delaunay)
Info    : [ 50%] Meshing surface 24 (Plane, Frontal-Delaunay)
Info    : Done meshing 2D (Wall 0.0233768s, CPU 0.084051s)
Info    : 785 nodes 1629 elements
Info    : Writing 't4.msh'...
Info    : Done writing 't4.msh'
Error   : Could not open file `/Users/davido/Documents/Gmsn/../t4_image.png'
Traceback (most recent call last):
  File "t4.py", line 180, in <module>
    gmsh.fltk.run()
  File "/Users/davido/anaconda3/lib/python3.7/site-packages/gmsh.py", line 10032, in run
    raise Exception(logger.getLastError())
Exception: Could not open file `/Users/davido/Documents/Gmsn/../t4_image.png'

原始脚本t4.py:

# ------------------------------------------------------------------------------
#
#  Gmsh Python tutorial 4
#
#  Holes in surfaces, annotations, entity colors
#
# ------------------------------------------------------------------------------

import gmsh
import math
import sys
import os

gmsh.initialize()

gmsh.model.add("t4")

cm = 1e-02
e1 = 4.5 * cm
e2 = 6 * cm / 2
e3 = 5 * cm / 2
h1 = 5 * cm
h2 = 10 * cm
h3 = 5 * cm
h4 = 2 * cm
h5 = 4.5 * cm
R1 = 1 * cm
R2 = 1.5 * cm
r = 1 * cm
Lc1 = 0.01
Lc2 = 0.003


def hypot(a, b):
    return math.sqrt(a * a + b * b)


ccos = (-h5 * R1 + e2 * hypot(h5, hypot(e2, R1))) / (h5 * h5 + e2 * e2)
ssin = math.sqrt(1 - ccos * ccos)

# We start by defining some points and some lines. To make the code shorter we
# can redefine a namespace:
factory = gmsh.model.geo
factory.addPoint(-e1 - e2, 0, 0, Lc1, 1)
factory.addPoint(-e1 - e2, h1, 0, Lc1, 2)
factory.addPoint(-e3 - r, h1, 0, Lc2, 3)
factory.addPoint(-e3 - r, h1 + r, 0, Lc2, 4)
factory.addPoint(-e3, h1 + r, 0, Lc2, 5)
factory.addPoint(-e3, h1 + h2, 0, Lc1, 6)
factory.addPoint(e3, h1 + h2, 0, Lc1, 7)
factory.addPoint(e3, h1 + r, 0, Lc2, 8)
factory.addPoint(e3 + r, h1 + r, 0, Lc2, 9)
factory.addPoint(e3 + r, h1, 0, Lc2, 10)
factory.addPoint(e1 + e2, h1, 0, Lc1, 11)
factory.addPoint(e1 + e2, 0, 0, Lc1, 12)
factory.addPoint(e2, 0, 0, Lc1, 13)

factory.addPoint(R1 / ssin, h5 + R1 * ccos, 0, Lc2, 14)
factory.addPoint(0, h5, 0, Lc2, 15)
factory.addPoint(-R1 / ssin, h5 + R1 * ccos, 0, Lc2, 16)
factory.addPoint(-e2, 0.0, 0, Lc1, 17)

factory.addPoint(-R2, h1 + h3, 0, Lc2, 18)
factory.addPoint(-R2, h1 + h3 + h4, 0, Lc2, 19)
factory.addPoint(0, h1 + h3 + h4, 0, Lc2, 20)
factory.addPoint(R2, h1 + h3 + h4, 0, Lc2, 21)
factory.addPoint(R2, h1 + h3, 0, Lc2, 22)
factory.addPoint(0, h1 + h3, 0, Lc2, 23)

factory.addPoint(0, h1 + h3 + h4 + R2, 0, Lc2, 24)
factory.addPoint(0, h1 + h3 - R2, 0, Lc2, 25)

factory.addLine(1, 17, 1)
factory.addLine(17, 16, 2)

# Gmsh provides other curve primitives than straight lines: splines, B-splines,
# circle arcs, ellipse arcs, etc. Here we define a new circle arc, starting at
# point 14 and ending at point 16, with the circle's center being the point 15:
factory.addCircleArc(14, 15, 16, 3)

# Note that, in Gmsh, circle arcs should always be smaller than Pi. The
# OpenCASCADE geometry kernel does not have this limitation.

# We can then define additional lines and circles, as well as a new surface:
factory.addLine(14, 13, 4)
factory.addLine(13, 12, 5)
factory.addLine(12, 11, 6)
factory.addLine(11, 10, 7)
factory.addCircleArc(8, 9, 10, 8)
factory.addLine(8, 7, 9)
factory.addLine(7, 6, 10)
factory.addLine(6, 5, 11)
factory.addCircleArc(3, 4, 5, 12)
factory.addLine(3, 2, 13)
factory.addLine(2, 1, 14)
factory.addLine(18, 19, 15)
factory.addCircleArc(21, 20, 24, 16)
factory.addCircleArc(24, 20, 19, 17)
factory.addCircleArc(18, 23, 25, 18)
factory.addCircleArc(25, 23, 22, 19)
factory.addLine(21, 22, 20)

factory.addCurveLoop([17, -15, 18, 19, -20, 16], 21)
factory.addPlaneSurface([21], 22)

# But we still need to define the exterior surface. Since this surface has a
# hole, its definition now requires two curves loops:
factory.addCurveLoop([11, -12, 13, 14, 1, 2, -3, 4, 5, 6, 7, -8, 9, 10], 23)
factory.addPlaneSurface([23, 21], 24)

# As a general rule, if a surface has N holes, it is defined by N+1 curve loops:
# the first loop defines the exterior boundary; the other loops define the
# boundaries of the holes.

factory.synchronize()

# Finally, we can add some comments by creating a post-processing view
# containing some strings:
v = gmsh.view.add("comments")

# Add a text string in window coordinates, 10 pixels from the left and 10 pixels
# from the bottom:
gmsh.view.addListDataString(v, [10, -10], ["Created with Gmsh"])

# Add a text string in model coordinates centered at (X,Y,Z) = (0, 0.11, 0),
# with some style attributes:
gmsh.view.addListDataString(v, [0, 0.11, 0], ["Hole"],
                            ["Align", "Center", "Font", "Helvetica"])

# If a string starts with `file://', the rest is interpreted as an image
# file. For 3D annotations, the size in model coordinates can be specified after
# a `@' symbol in the form `widthxheight' (if one of `width' or `height' is
# zero, natural scaling is used; if both are zero, original image dimensions in
# pixels are used):
png = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir,
                   't4_image.png')
print('Hey! png = ', png)
gmsh.view.addListDataString(v, [0, 0.09, 0], ["file://" + png + "@0.01x0"],
                            ["Align", "Center"])

# The 3D orientation of the image can be specified by proving the direction
# of the bottom and left edge of the image in model space:
gmsh.view.addListDataString(v, [-0.01, 0.09, 0],
                            ["file://" + png + "@0.01x0,0,0,1,0,1,0"])

# The image can also be drawn in "billboard" mode, i.e. always parallel to
# the camera, by using the `#' symbol:
gmsh.view.addListDataString(v, [0, 0.12, 0], ["file://" + png + "@0.01x0#"],
                            ["Align", "Center"])

# The size of 2D annotations is given directly in pixels:
gmsh.view.addListDataString(v, [150, -7], ["file://" + png + "@20x0"])

# These annotations are handled by a list-based post-processing view. For
# large post-processing datasets, that contain actual field values defined on
# a mesh, you should use model-based post-processing views instead, which
# allow to efficiently store continuous or discontinuous scalar, vector and
# tensor fields, or arbitrary polynomial order.

# Views and geometrical entities can be made to respond to double-click
# events, here to print some messages to the console:
gmsh.view.option.setString(v, "DoubleClickedCommand",
                           "Printf('View[0] has been double-clicked!');")
gmsh.option.setString(
    "Geometry.DoubleClickedLineCommand",
    "Printf('Curve %g has been double-clicked!', "
    "Geometry.DoubleClickedEntityTag);")

# We can also change the color of some entities:
gmsh.model.setColor([(2, 22)], 127, 127, 127)  # Gray50
gmsh.model.setColor([(2, 24)], 160, 32, 240)  # Purple
gmsh.model.setColor([(1, i) for i in range(1, 15)], 255, 0, 0)  # Red
gmsh.model.setColor([(1, i) for i in range(15, 21)], 255, 255, 0)  # Yellow

gmsh.model.mesh.generate(2)

gmsh.write("t4.msh")

# Launch the GUI to see the results:
if '-nopopup' not in sys.argv:
    gmsh.fltk.run()

gmsh.finalize()

1 个回答

0

因为在网格中打孔正是我需要做的事情,所以我想让这个例子能够正常工作。

首先,我发现如果我关闭 gmsh.fltk.run() 这个功能,脚本就会正常结束,没有错误,并且网格会被写入,但不会显示出来。

之后,我可以在命令行或脚本启动的图形界面中打开 t4.msh 文件,查看它。

接着我发现,整个 t4_image.png 这一部分对于这个例子的主要功能来说是多余的,所以只要选择不生成这个可选的静态图像,就能解决我的问题。

if False:
    # If a string starts with `file://', the rest is interpreted as an image
    # file. For 3D annotations, the size in model coordinates can be specified after
    # a `@' symbol in the form `widthxheight' (if one of `width' or `height' is
    # zero, natural scaling is used; if both are zero, original image dimensions in
    # pixels are used):
    gmsh.view.addListDataString(v, [0, 0.09, 0], ["file://../t4_image.png@0.01x0"],
                                ["Align", "Center"])

    # The 3D orientation of the image can be specified by proving the direction
    # of the bottom and left edge of the image in model space:
    gmsh.view.addListDataString(v, [-0.01, 0.09, 0],
                                ["file://../t4_image.png@0.01x0,0,0,1,0,1,0"])

    # The image can also be drawn in "billboard" mode, i.e. always parallel to
    # the camera, by using the `#' symbol:
    gmsh.view.addListDataString(v, [0, 0.12, 0],
                                ["file://../t4_image.png@0.01x0#"],
                                ["Align", "Center"])

    # The size of 2D annotations is given directly in pixels:
    gmsh.view.addListDataString(v, [150, -7], ["file://../t4_image.png@20x0"])

Gmsh t4.py example with .png stuff supressed

撰写回答