5.执行算术运算
在许多情况下,算术运算用于设置变量值。这只需使用前面示例代码中的赋值就可以完成。
通常需要在不关心表达式结果的情况下触发表达式的计算;目的是计算的一些副作用,例如修改一些数组项。原则上,这可以通过对“dummy(虚拟)”变量进行赋值来实现,该变量的值不被使用:
dummy := for j := 1 to n do a[j] := 1 / j^2
但是,不需要使用虚拟变量;也可以使用命令calc:
calc for j := 1 to n do a[j] := 1 / j^2
使用该命令,可以使用任何表达式,然后对其进行一次计算,并忽略其结果。在计算多个表达式时,不需要为每个表达式使用一个calc命令,但可以使用复合表达式:
calc
begin
for j := 1 to n do a[j] := 1 / j^2;
for j := 0 to 2 * n do b[j] := j^2;
end
(请注意,这些行需要缩进,以便它们被视为属于calc命令。)
除了begin / end,还可以使用括号:
calc (for j := 1 to n do a[j] := 1 / j^2;
for j := 0 to 2 * n do b[j]:= j^2)
在任何情况下,复合表达式的各个部分都用分号分隔。
有时,需要使用“!”命令而不是calc:
! f := 1 / A_max^2
不同之处在于,在这种情况下,不会立即执行计算,但只有当图形图表绘制到“!”命令。
6.控制结构
通常,一个脚本是逐行读取和执行的,但是有各种各样的控制结构来影响执行流程。
if命令允许在满足给定条件的情况下执行其他语句。
例子:
if a < 0 then
show"a is negative!"
建议在新的行中开始then部分,并使用一些缩进以提高清晰度。此外,还可以添加一个在条件未满足时执行的else部分:
if a < 0 then
show"a < 0 !!!"
else
show"Ok"
可以使用begin和end之间的块,而不是单个命令:
if a < 0 then
begin
show "Problem: a < 0"
b := 0
end
else
begin
b := sqrt(a)
show "Ok"
end
注意,begin和end应该总是单独出现在一行中。此外,在“then”后面可以有一个命令,也可以没有任何命令,但不只是一个注释。
在下文中,我们将“statement”一词用于以下内容之一:
l 单一命令
l begin和end之间的一组命令
l 控制结构
对于“for”语句,可以对给定范围的每个值解释一次以下语句。例子:
for x := 1 to 10 do show x, ", ",sin(x):f6
将使用不同的x值执行show命令。循环命令可以位于同一行(如上所述)或下一行(最好使用缩进以提高可读性,或者在begin和end之间可以有一个命令块)。后者的一个例子:
y := 0
for j := 0 to 10 do
begin
x := sqrt(j)
y := y + x
show x:d3, ", ", y:d3
end
还允许按以下方式指定值列表(以“|”分隔):
for x := 1 | 2 | 5 | 10 do
show x, " ", 10 * lg(x):f1
如果值的范围为空(例如,for j := 1 to 0),则根本不执行命令或块。
使用“while”可以构造一个循环,在该循环中,只要满足某个条件,命令(或命令块)就会被一次又一次地解释。例子:
j := 1
while j < 5 do
show j := j + 1
使用“repeat”语句,可以构造一个循环,其中一个命令块(这里不需要begin和end)被一次又一次地解释,直到满足某个条件为止。
例子:
repeat
j := rnd(5)
show j:f3
until j < 1
允许组合所有控制结构。例如,可以使用嵌套for循环来运行某些二维空间:
for x := 1 to 10 do
for y := 0 to 1 step 0.1 do
showx:d4, " ", y:d4, " ", sin(x) * cos(y)
另一个示例是将if-then语句作为if-then-else语句的else部分:
if x > 0 then
show "positive"
else if x < 0 then
show "negative"
else
show "zero"
请注意,在数学表达式中可以使用类似的控制结构;这些控制结构不应与脚本命令的控制结构混淆。例如,请参见以下函数定义:
set_a(n, x) := (for j := 1 to n do a[j] :=x^j; a[n])
此外,还有goto语句,用于直接跳转到脚本中的某个位置。goto之后,通常只有一些标签(比如变量名),或者括号中的表达式,可以从中计算标签。软件将搜索一行以冒号开头,紧跟标签,不包含任何其他内容(甚至不包含空白字符或注释)。例子:
goto TEST
show "This is not shown.”
:TEST
show "This is shown."
请注意,使用goto可以跳出任何其他控制结构,但不能跳转到其他控制结构里。
建议仅出于简单目的使用goto,而不用于一般替换其他控制结构,如repeat-until。
命令ignore允许告诉脚本解释器在找到命令ignoreoff之前,应忽略以下命令。这类似于代码的“注释”部分。
您还可以指定一个条件,例如
ignore if max >= 10
因此,只有满足条件时才会忽略以下内容。
最后,通过命令terminate,可以提前终止脚本的执行(甚至从include文件)。使用terminateprogram,您甚至可以终止软件的执行;您还可以在其后面指定一个退出代码编号,作为括号中的表达式;该值可以通过调用软件的批量作业进行测试。此外,可以用terminate program when finished让软件只有在完成脚本执行(包括图形)后才终止。使用terminatefile,只能跳过执行当前include文件的其余部分。
7.各种有用的命令
使用defarray命令,可以定义数组
defarray a[1, 10, 0.1]
前两个参数是第一个和最后一个数组索引,第三个(可选)参数是步骤大小。调用之后,可以分配和检索数组值:
calc for j := 1 to 10 step 0.1 do a[j] :=rnd(1)
show a[1]:f3
readlist命令可用于从数字列表中读取数组内容。当大数组必须由来自其他程序的数值数据填充时,这很方便。数字列表由不同的行组成,每行至少以一个空格开头,由一列或多列数字组成,用逗号分隔或简单地用空格分隔。在列表之前,您要定义输入到哪些变量。例子:
readlist k, a[k]:
0, 1
1, 6
2, 3
8.保留上一个脚本执行的结果
通常,当执行脚本时,软件将首先删除先前脚本执行所产生的任何数据(变量、数组、用户定义函数、存储脉冲和光束传播结果),这样获得的结果将永远不会依赖于先前的执行(除非已创建文件,然后再次读取)。但是,可以使用命令keep禁止删除,该命令必须放在脚本的第一行。可以指明要保留什么,例如
keep variables, arrays, functions, results
(其中results表示计算结果,例如来自模式求解器或来自光束传播的结果)
或者只是使用
keep all
此功能非常有用,例如用于调试:在执行生成意外结果或错误消息的脚本之后,可以运行另一个脚本(包含keep命令)以显示其他信息。如果再次执行原始脚本是费时的(为调试添加输出),这将非常有用。
这个特性的另一个方便的应用是,如果您执行了一个脚本,该脚本完成了一些耗时的计算,并且后来意识到您忘记了包含一些用于显示或保存结果的命令,或者这些命令有问题。然后,您可以在原始脚本中包含或更正这些命令,但您可以将这些命令复制到另一个以keep all开头的短脚本中,而不是再次执行它。这样,您只需执行显示或保存结果的命令,而不必再次进行耗时的计算。
建议仅将该功能用于上面解释的特殊目的,而不是常规用途,因为如果结果依赖于以前的脚本执行,则可能很难重现结果。
9.模型定义概述
现在我们开始考虑物理模型。通过调用数学表达式中的某些函数来定义和使用这些模型:
l 一些函数定义或修改物理模型的细节。例如,函数addinputchannel()定义了光纤放大器或激光器的光信道。
l 其他函数用于从模型中获得计算结果。例如,函数p_out()可用于获得光信道的输出功率。
我们将首先讨论函数在定义模型时的使用。
定义光纤所有参数的建议方法是将所有相应的函数调用组合到一个函数中(跨越多行),然后调用该函数。这样,以后可以修改模型的某些参数,并再次调用该函数以设置这些值。
给出了一个简单的例子,其中假设已经定义了各种变量(例如,r_c=纤芯半径,n_dop=掺杂剂浓度等),各种函数的具体细节解释如下:
def_model() :=
begin
global allow all;
set_fiber(L_f, N_z, gainsystem$);
add_ring(r_c, N_dop);
pump := addinputchannel(P_p_in, l_p, 'I_p',loss_p, backward);
sign := addinputchannel(P_s_in, l_s, 'I_s',loss_s, forward);
finish_fiber();
end;
calc def_model()
不要忘记最后一行——如果没有它,函数def_model()将被定义,但不会被执行。
稍后可以修改一些参数并再次调用函数def_model(),以使更改生效。(请注意,仅更改光纤长度L_f等变量值是不够的;只有在调用def_model()时,才会调用这些变量的值并将其放入模型中。)
在def_model()的定义中,您必须遵守以下规则:
.首先调用set_fiber(),以初始化光纤定义并定义光纤的基本参数。
.如果强度分布存在方位角依赖性,请调用set_phi_steps()定义方位角步长。(上述示例中不需要这样做。)
.在某些情况下,矩形网格更可取。这可以通过set_xy_steps(x_min, x_max, dx, y_min, y_max, dy)之类的函数调用来完成,该函数定义了最小和最大x和y值以及步长大小。
.然后调用add_ring()定义掺杂剂的径向结构。
.然后通过调用函数addinputchannel()和/或addASEchannel()定义所有光信道。
. 最后,调用finish_fiber()以告诉软件光纤定义已完成。
以下小节提供了有关定义光纤参数和光信道的更多详细信息。
请注意,所有程序特定的函数都在假设使用基本的国际单位制单位的情况下处理具有尺寸的值。例如,假定光纤长度和波长以米(而非纳米)为单位,光功率以瓦特为单位等