本节适用于运行过 FLAC3D(至少了解软件简单的操作流程)但尚未使用 FISH 语言的用户。为了方便接下来的学习,强烈建议大家手动敲一下本章所有代码。个人以为,学习编程语言的最好方式就是写代码复现结果,让自己在不断试错过程中成长。
FISH文件中主要含有两种结构:1)独立成行的FISH语句(inline fish),这些语句必须包含在一对中括号内;2)函数(function),该结构以 fish define 开头,以 end 结尾。函数可以调用其它函数,被调用的函数还可以进一步调用其他函数,依此类推。定义函数的顺序无关紧要,只要它们都是在使用之前被定义即可。
为了方便读者验证代码,后续章节代码结构如下:
model new ;清空内存,开始一个新的分析
fish define 函数名(形参) ;形参可选
变量定义
功能定义
end
[函数名(实参)] ;执行函数
program return ;立即返回控制权给用户,在进行代码调试时,也可以在相应的位置插入该语句 值得注意的是:model new命令会清空内存。因此,对于一个完整的分析(有可能包含好几个文件),只在主控文件中含有model new命令。
简单的FISH函数
FISH语言中,如不对变量或者函数进行显式声明,它们默认是全局变量。为了避免出错,本笔记中所有的变量都进行了显式声明,本人也强烈建议大家都这样做。
下面的代码片段中,包含一个函数fname和两个独立成行的FISH语句([fname]和[ab])。函数中显式声明了两个局部(local)变量a和b并对其进行赋值,以及一个全局变量ab。
若程序执行成功,执行[fname]后将返回0,表示调用成功。由于变量ab是全局变量,因此ab可在函数外被调用,执行[ab]后返回5(2+3)。如果在函数外调用局部变量,如执行[a]将报错,局部变量只能在所定义的函数快中被使用。
model new
fish define fname
local a=2, b=3
global ab=a+b
end
[fname] ; 0(没有返回值,自动返回0)
[ab] ; 5
program return
进一步,上述函数可修改为带有形参输入。跟其他编程语言不同,形参是临时变量,函数运行结束后自动消失,无需显式声明。
model new
fish define fname(a,b)
global ab=a+b
end
[fname(2,3)] ; 0
[ab] ; 5
program return
已知的杨氏模量和泊松比可以计算体积模量和剪切模量,他们之间的相互关系如下:
G=E/(1+\nu)
K=E/3(1-2\nu)
model new
fish define derive(y_mod,p_ratio)
global s_mod=y_mod/(2.0*(1.0+p_ratio))
global b_mod=y_mod/(3.0*(1.0-2.0*p_ratio))
end
program return
作为全局变量的s_mod和b_mod可以作为后续FLAC3D命令行中的参数(需要包含在中括号中),将上一个例子修改为
model new
fish define derive(y_mod,p_ratio)
global s_mod=y_mod/(2.0*(1.0+p_ratio))
global b_mod=y_mod/(3.0*(1.0-2.0*p_ratio))
end
[derive(5e8,0.25)]
;全局变量s_mod和b_mod作为后续FLAC3D命令行中的参数
zone create brick size (2,2,2) ;建立模型,创建一个2X2X2的网格
zone cmodel assign elastic ;指定材料本构模型
zone property bulk [b_mod] shear [s_mod] ;赋予材料参数
;未完待续
program return
带返回值的函数
如果调用函数后需要返回值,可通过以下两种方式:1)利用return语句;2)对函数名直接赋值
model new
;利用return语句
fish define fname(a,b)
return a+b
end
[fname(2,3)] ; 5
;对函数名直接赋值
fish define fname(a,b)
global fname=a+b
end
[fname(2,3)] ; 5
program return
如果表达式过长,为了方便阅读,除了可以设置中间变量外,还可以利用续行符“...” 。
model new
fish define long_sum
local a1=1,a2=2,a3=3,a4=4,a5=5,a6=6,a7=7,a8=8,a9=9,a10=10
;设置中间变量temp
local temp = a1+a2+a3+a4+a5
global long_sum = temp+a6+a7+a8+a9+a10
;利用续航符 “...”
global long_sum = a1+a2+a3+a4+a5+...
a6+a7+a8+a9+a10
end
[long_sum]
program return
FLAC3D命令和FISH命令的联合使用
在上述计算体积模量和剪切模量代码中,是在FLAC3D的命令行中简单的嵌入了FISH函数。实际上,FISH函数中同样可以嵌入FLAC3D命令。为了实现这一目的,需将FLAC3D命令包含在command...endcommand代码块中。下面的例子就是通过简单的函数调用,创建了一个2X2X2的网格。当然,配合FISH的循环和控制命令,可实现更加复杂的建模和分析。
model new
fish define fname
command
zone create brick size 2 2 2
endcommand
end
[fname]
program return
输入和输出
在FISH代码中可利用内置函数io.out(a)输出变量a中的内容到控制台。如果变量不是字符串,则会强制进行变量转换。如第一个代码
model new
fish define fname
local a=2, b=3
global ab=a+b
io.out(ab) ; 5
end
[fname] ; 0(没有返回值,自动返回0)
program return
控制台将输出5和0。配合下一章的字符串,输出的内容可更加丰富。
还可以利用内置函数http://io.in(s)在控制台进行参数输入。变量s是字符串变量,可用于提示输入的内容。如果输入的内容可被编译器解析成一数值(整数或实数),则函数返回相应的数值。如果输入的内容无法被解析成数值型(如字符或字符串),则输入的内容会以字符串的形式返回。可以借助内置的type()函数查看函数返回内容的类型。
model new
fish define fname
local a=io.in("input a ")
local b=io.in("input b ")
global ab=a+b
io.out(ab)
end
[fname] ; 0(没有返回值,自动返回0)
program return
多文件管理
对于复杂分析,往往按照代码功能将代码拆分成若干独立文件,比如上述计算体积模量和剪切模量代码可以分成三个独立文件:1)主控文件main(一个完整的分析一般只含一个主控文件);2)专门存储fish命令的文件,一般包含所有的函数和全局变量申明。全局变量的申明可以通过函数结构,也可以是通过独立成行的FISH语句;3)和模型计算相关的文件,按功能可以分为模型的初始化(网格导入、指定材料,初始边界条件,全过程监控变量等)、各分析步中相关的操作(如开挖,堆载、施加支护等)、后处理等。
;主文件 main.f3dat
model new
program call "fish"
program call "initial"
program return
;fish文件 fish.f3dat
fish define derive(y_mod,p_ratio)
global s_mod=y_mod/(2.0*(1.0+p_ratio))
global b_mod=y_mod/(3.0*(1.0-2.0*p_ratio))
end
[derive(5e8,0.25)]
;initial.f3dat
zone create brick size (2,2,2) ;建立模型,创建一个2X2X2的网格
zone cmodel assign elastic ;指定材料
zone property bulk [b_mod] shear [s_mod] ;赋予材料参数
;未完待续
再谈变量作用域
默认情况下,变量名和函数名都是全局变量。全局变量可以通过在控制台输入“fish list symbols”命令查看,或者在GUI界面的“FISH Global Symbols”面板查看。
全局变量可以在一个函数定义,然后在另一个函数中被使用。甚至,全局变量可以在一个文件中定义,然后在另一个文件中被使用,如本章的最后一个例子。局部变量的作用域仅限于定义它的那个函数。当函数被执行后,局部变量自动消失。
鉴于FLAC3D的编译器对于变量的检查有限,为了防止变量误用(默认情况下,当遇到未定义的变量时,编译器会自动创建一个全局变量而不报错)和方便调试,FLAC3D建议将软件自动创建全局变量的功能取消(可通过在主控文件中“model new”后添加“fish automatic-create off”实现)。这样,所有的变量名和函数名在使用时都需要进行显式的声明。